3 require "time" # for Time.httpdate
13 status
, headers
, body
= @app.call(env)
14 headers
= Utils
::HeaderHash.new(headers
)
16 # Skip compressing empty entity body responses and responses with
18 if Utils
::STATUS_WITH_NO_ENTITY_BODY.include?(status
) ||
19 headers
['Cache-Control'].to_s
=~
/\bno-transform\b/
20 return [status
, headers
, body
]
23 request
= Request
.new(env)
25 encoding
= Utils
.select_best_encoding(%w(gzip deflate identity
),
26 request
.accept_encoding
)
28 # Set the Vary HTTP header.
29 vary
= headers
["Vary"].to_s
.split(",").map
{ |v
| v
.strip
}
30 unless vary
.include?("*") || vary
.include?("Accept-Encoding")
31 headers
["Vary"] = vary
.push("Accept-Encoding").join(",")
36 mtime
= headers
.key
?("Last-Modified") ?
37 Time
.httpdate(headers
["Last-Modified"]) : Time
.now
38 body
= self.class.gzip(body
, mtime
)
39 size
= Rack
::Utils.bytesize(body
)
40 headers
= headers
.merge("Content-Encoding" => "gzip", "Content-Length" => size
.to_s
)
41 [status
, headers
, [body
]]
43 body
= self.class.deflate(body
)
44 size
= Rack
::Utils.bytesize(body
)
45 headers
= headers
.merge("Content-Encoding" => "deflate", "Content-Length" => size
.to_s
)
46 [status
, headers
, [body
]]
48 [status
, headers
, body
]
50 message
= "An acceptable encoding for the requested resource #{request.fullpath} could not be found."
51 [406, {"Content-Type" => "text/plain", "Content-Length" => message
.length
.to_s
}, [message
]]
55 def self.gzip(body
, mtime
)
57 gzip
= Zlib
::GzipWriter.new(io
)
61 body
.each
{ |part
| gzip
<< part
}
68 Zlib
::DEFAULT_COMPRESSION,
69 # drop the zlib header which causes both Safari and IE to choke
72 Zlib
::DEFAULT_STRATEGY
75 # Loosely based on Mongrel's Deflate handler
76 def self.deflate(body
)
77 deflater
= Zlib
::Deflate.new(*DEFLATE_ARGS
)
80 body
.each
{ |part
| deflater
<< part
}
82 return deflater
.finish