Skip to content
Newer
Older
100644 97 lines (83 sloc) 2.66 KB
a31ee95 @qerub Implemented Rack::Deflater
qerub authored
1 require "zlib"
cabc20d added gzip support to Rack::Deflater
Ben authored
2 require "stringio"
e44d908 Fixed Rack::Deflater to handle responses with Last-Modified header
Dan Kubb authored
3 require "time" # for Time.httpdate
d6fa6af @josh Explicitly require request, response, and utils
josh authored
4 require 'rack/utils'
a31ee95 @qerub Implemented Rack::Deflater
qerub authored
5
6 module Rack
2f79f55 @josh Deflater sets Content-Length header [#9 state:resolved]
josh authored
7 class Deflater
8 def initialize(app)
9 @app = app
3b11658 Added Accept-Encoding to HTTP Vary header
Dan Kubb authored
10 end
11
2f79f55 @josh Deflater sets Content-Length header [#9 state:resolved]
josh authored
12 def call(env)
13 status, headers, body = @app.call(env)
14 headers = Utils::HeaderHash.new(headers)
15
16 # Skip compressing empty entity body responses and responses with
17 # no-transform set.
18 if Utils::STATUS_WITH_NO_ENTITY_BODY.include?(status) ||
71030b9 @josh Revert "Add common HTTP strings to Rack::Const"
josh authored
19 headers['Cache-Control'].to_s =~ /\bno-transform\b/
2f79f55 @josh Deflater sets Content-Length header [#9 state:resolved]
josh authored
20 return [status, headers, body]
21 end
22
23 request = Request.new(env)
24
25 encoding = Utils.select_best_encoding(%w(gzip deflate identity),
26 request.accept_encoding)
27
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(",")
32 end
33
34 case encoding
35 when "gzip"
71030b9 @josh Revert "Add common HTTP strings to Rack::Const"
josh authored
36 headers['Content-Encoding'] = "gzip"
37 headers.delete('Content-Length')
38 mtime = headers.key?("Last-Modified") ?
39 Time.httpdate(headers["Last-Modified"]) : Time.now
c81542e @rtomayko Rack::Deflater streaming
rtomayko authored
40 [status, headers, GzipStream.new(body, mtime)]
2f79f55 @josh Deflater sets Content-Length header [#9 state:resolved]
josh authored
41 when "deflate"
71030b9 @josh Revert "Add common HTTP strings to Rack::Const"
josh authored
42 headers['Content-Encoding'] = "deflate"
43 headers.delete('Content-Length')
c81542e @rtomayko Rack::Deflater streaming
rtomayko authored
44 [status, headers, DeflateStream.new(body)]
2f79f55 @josh Deflater sets Content-Length header [#9 state:resolved]
josh authored
45 when "identity"
46 [status, headers, body]
47 when nil
3576a34 @rtomayko Fix spec failures in Rack::Deflator under 1.9
rtomayko authored
48 message = "An acceptable encoding for the requested resource #{request.fullpath} could not be found."
71030b9 @josh Revert "Add common HTTP strings to Rack::Const"
josh authored
49 [406, {"Content-Type" => "text/plain", "Content-Length" => message.length.to_s}, [message]]
2f79f55 @josh Deflater sets Content-Length header [#9 state:resolved]
josh authored
50 end
a31ee95 @qerub Implemented Rack::Deflater
qerub authored
51 end
52
c81542e @rtomayko Rack::Deflater streaming
rtomayko authored
53 class GzipStream
54 def initialize(body, mtime)
55 @body = body
56 @mtime = mtime
57 end
cabc20d added gzip support to Rack::Deflater
Ben authored
58
c81542e @rtomayko Rack::Deflater streaming
rtomayko authored
59 def each(&block)
60 @writer = block
61 gzip =::Zlib::GzipWriter.new(self)
62 gzip.mtime = @mtime
b0f49bd @josh Use more compatible gzip write api instead of "<<".
josh authored
63 @body.each { |part| gzip.write(part) }
c81542e @rtomayko Rack::Deflater streaming
rtomayko authored
64 @body.close if @body.respond_to?(:close)
65 gzip.close
66 @writer = nil
67 end
cabc20d added gzip support to Rack::Deflater
Ben authored
68
c81542e @rtomayko Rack::Deflater streaming
rtomayko authored
69 def write(data)
70 @writer.call(data)
71 end
2f79f55 @josh Deflater sets Content-Length header [#9 state:resolved]
josh authored
72 end
cabc20d added gzip support to Rack::Deflater
Ben authored
73
c81542e @rtomayko Rack::Deflater streaming
rtomayko authored
74 class DeflateStream
75 DEFLATE_ARGS = [
76 Zlib::DEFAULT_COMPRESSION,
77 # drop the zlib header which causes both Safari and IE to choke
78 -Zlib::MAX_WBITS,
79 Zlib::DEF_MEM_LEVEL,
80 Zlib::DEFAULT_STRATEGY
81 ]
f3b542a @qerub deflater.rb - Move out the Zlib::Deflate constructor arguments to a c…
qerub authored
82
c81542e @rtomayko Rack::Deflater streaming
rtomayko authored
83 def initialize(body)
84 @body = body
85 end
a31ee95 @qerub Implemented Rack::Deflater
qerub authored
86
c81542e @rtomayko Rack::Deflater streaming
rtomayko authored
87 def each
88 deflater = ::Zlib::Deflate.new(*DEFLATE_ARGS)
89 @body.each { |part| yield deflater.deflate(part) }
90 @body.close if @body.respond_to?(:close)
91 yield deflater.finish
92 nil
93 end
2f79f55 @josh Deflater sets Content-Length header [#9 state:resolved]
josh authored
94 end
a31ee95 @qerub Implemented Rack::Deflater
qerub authored
95 end
96 end
Something went wrong with that request. Please try again.