Skip to content
Browse files

Implemented Rack::Deflater

  • Loading branch information...
1 parent 0f2dab5 commit a31ee950d37b123b8b32c792ab448bb57e707431 @qerub qerub committed with Jul 2, 2008
Showing with 96 additions and 0 deletions.
  1. +1 −0 lib/rack.rb
  2. +44 −0 lib/rack/deflater.rb
  3. +51 −0 test/spec_rack_deflater.rb
View
1 lib/rack.rb
@@ -30,6 +30,7 @@ def self.release
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"
View
44 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
View
51 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

0 comments on commit a31ee95

Please sign in to comment.
Something went wrong with that request. Please try again.