summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAaron Patterson <aaron.patterson@gmail.com>2015-05-26 14:35:11 -0700
committerAaron Patterson <aaron.patterson@gmail.com>2015-05-26 14:35:11 -0700
commite73ca98cf8684d5f8313eb8d48f2c7f57588bb68 (patch)
treeaf6eb59c3389e150f0d0f6bcfa3242bba119a8b6
parentd7c6b75a66f793f27398abb6932b4a540bf996ec (diff)
parent421932740bb8395f908759124c2727eab9cd6b54 (diff)
downloadrack-e73ca98cf8684d5f8313eb8d48f2c7f57588bb68.tar.gz
Merge pull request #863 from jeremyevans/static_gzip
Add support for serving gzipped static files
-rw-r--r--lib/rack/static.rb22
-rw-r--r--test/cgi/test.gzbin0 -> 165 bytes
-rw-r--r--test/spec_static.rb28
3 files changed, 48 insertions, 2 deletions
diff --git a/lib/rack/static.rb b/lib/rack/static.rb
index ec9ec91f..f401abeb 100644
--- a/lib/rack/static.rb
+++ b/lib/rack/static.rb
@@ -84,6 +84,7 @@ module Rack
@app = app
@urls = options[:urls] || ["/favicon.ico"]
@index = options[:index]
+ @gzip = options[:gzip]
root = options[:root] || Dir.pwd
# HTTP Headers
@@ -110,9 +111,26 @@ module Rack
path = env[PATH_INFO]
if can_serve(path)
- env[PATH_INFO] = (path =~ /\/$/ ? path + @index : @urls[path]) if overwrite_file_path(path)
+ if overwrite_file_path(path)
+ env[PATH_INFO] = (path =~ /\/$/ ? path + @index : @urls[path])
+ elsif @gzip && env['HTTP_ACCEPT_ENCODING'] =~ /\bgzip\b/
+ path = env[PATH_INFO]
+ env[PATH_INFO] += '.gz'
+ response = @file_server.call(env)
+ env[PATH_INFO] = path
+
+ if response[0] == 404
+ response = nil
+ else
+ if mime_type = Mime.mime_type(::File.extname(path), 'text/plain')
+ response[1][CONTENT_TYPE] = mime_type
+ end
+ response[1]['Content-Encoding'] = 'gzip'
+ end
+ end
+
path = env[PATH_INFO]
- response = @file_server.call(env)
+ response ||= @file_server.call(env)
headers = response[1]
applicable_rules(path).each do |rule, new_headers|
diff --git a/test/cgi/test.gz b/test/cgi/test.gz
new file mode 100644
index 00000000..312c60e2
--- /dev/null
+++ b/test/cgi/test.gz
Binary files differ
diff --git a/test/spec_static.rb b/test/spec_static.rb
index fed1df25..2fac80b2 100644
--- a/test/spec_static.rb
+++ b/test/spec_static.rb
@@ -1,6 +1,8 @@
require 'rack/static'
require 'rack/lint'
require 'rack/mock'
+require 'zlib'
+require 'stringio'
class DummyApp
def call(env)
@@ -18,10 +20,12 @@ describe Rack::Static do
OPTIONS = {:urls => ["/cgi"], :root => root}
STATIC_OPTIONS = {:urls => [""], :root => "#{root}/static", :index => 'index.html'}
HASH_OPTIONS = {:urls => {"/cgi/sekret" => 'cgi/test'}, :root => root}
+ GZIP_OPTIONS = {:urls => ["/cgi"], :root => root, :gzip=>true}
@request = Rack::MockRequest.new(static(DummyApp.new, OPTIONS))
@static_request = Rack::MockRequest.new(static(DummyApp.new, STATIC_OPTIONS))
@hash_request = Rack::MockRequest.new(static(DummyApp.new, HASH_OPTIONS))
+ @gzip_request = Rack::MockRequest.new(static(DummyApp.new, GZIP_OPTIONS))
it "serves files" do
res = @request.get("/cgi/test")
@@ -70,6 +74,30 @@ describe Rack::Static do
res.body.should == "Hello World"
end
+ it "serves gzipped files if client accepts gzip encoding and gzip files are present" do
+ res = @gzip_request.get("/cgi/test", 'HTTP_ACCEPT_ENCODING'=>'deflate, gzip')
+ res.should.be.ok
+ res.headers['Content-Encoding'].should.equal 'gzip'
+ res.headers['Content-Type'].should.equal 'text/plain'
+ Zlib::GzipReader.wrap(StringIO.new(res.body), &:read).should =~ /ruby/
+ end
+
+ it "serves regular files if client accepts gzip encoding and gzip files are not present" do
+ res = @gzip_request.get("/cgi/rackup_stub.rb", 'HTTP_ACCEPT_ENCODING'=>'deflate, gzip')
+ res.should.be.ok
+ res.headers['Content-Encoding'].should.equal nil
+ res.headers['Content-Type'].should.equal 'text/x-script.ruby'
+ res.body.should =~ /ruby/
+ end
+
+ it "serves regular files if client does not accept gzip encoding" do
+ res = @gzip_request.get("/cgi/test")
+ res.should.be.ok
+ res.headers['Content-Encoding'].should.equal nil
+ res.headers['Content-Type'].should.equal 'text/plain'
+ res.body.should =~ /ruby/
+ end
+
it "supports serving fixed cache-control (legacy option)" do
opts = OPTIONS.merge(:cache_control => 'public')
request = Rack::MockRequest.new(static(DummyApp.new, opts))