Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Added GzFile for serving gzipped static files

  • Loading branch information...
commit 6b5dcfcf93cc34f2bfd1f435ae29548018315f2c 1 parent 7b535cd
@jbaudanza authored
View
1  lib/rack.rb
@@ -34,6 +34,7 @@ def self.release
autoload :ContentType, "rack/content_type"
autoload :ETag, "rack/etag"
autoload :File, "rack/file"
+ autoload :GzFile, "rack/gz_file"
autoload :Deflater, "rack/deflater"
autoload :Directory, "rack/directory"
autoload :ForwardRequest, "rack/recursive"
View
41 lib/rack/gz_file.rb
@@ -0,0 +1,41 @@
+module Rack
+ # Rack::GzFile behaves exactly the same as Rack::File, except that it will
+ # also serve up a gzip encoding of a file, if one is available on the
+ # filesystem.
+ #
+ # For each request, Rack::GzFile first checks the filesystem for a file with a
+ # .gz extension. If one is found, the appropriate encoding headers are added
+ # to the response and the gzip file is served.
+ #
+ # If no .gz file is found, Rack::GzFile will behave exactly like Rack::File.
+ class GzFile
+ def initialize(root, headers={}, default_mime = 'text/plain')
+ @file_server = Rack::File.new(root, headers, default_mime)
+ @default_mime = default_mime
+ end
+
+ def call(env)
+ path_info = env['PATH_INFO']
+
+ status, headers, body = @file_server.call(
+ env.merge('PATH_INFO' => path_info + '.gz')
+ )
+
+ gzip_available = status != 404
+
+ if !gzip_available || env['HTTP_ACCEPT_ENCODING'] !~ /\bgzip\b/
+ status, headers, body = @file_server.call(env)
+ else
+ headers['Content-Type'] = Mime.mime_type(::File.extname(path_info),
+ @default_mime)
+ headers['Content-Encoding'] = 'gzip'
+ end
+
+ if gzip_available
+ headers['Vary'] = 'Accept-Encoding'
+ end
+
+ [status, headers, body]
+ end
+ end
+end
View
1  test/cgi/assets/compress_me.html
@@ -0,0 +1 @@
+Hello, Rack!
View
BIN  test/cgi/assets/compress_me.html.gz
Binary file not shown
View
43 test/spec_gz_file.rb
@@ -0,0 +1,43 @@
+require 'rack/gz_file'
+require 'rack/lint'
+require 'rack/mock'
+require 'zlib'
+
+describe Rack::GzFile do
+ DOCROOT = File.expand_path(File.dirname(__FILE__)) unless defined? DOCROOT
+
+ def request
+ Rack::MockRequest.new(Rack::Lint.new(Rack::GzFile.new(DOCROOT)))
+ end
+
+ should "serve an uncompressed file when gzip is not supported by the server" do
+ res = request.get('/cgi/assets/index.html')
+ res.body.should.equal "### TestFile ###\n"
+ res.headers.should.not.include 'Vary'
+ res.headers.should.not.include('Content-Encoding')
+ res.headers['Content-Length'].should.equal(
+ File.size(DOCROOT + '/cgi/assets/index.html').to_s)
+ end
+
+ should "serve an uncompressed file when gzip is not supported by the client" do
+ res = request.get('/cgi/assets/compress_me.html')
+ res.body.should.equal 'Hello, Rack!'
+ res.headers['Vary'].should.equal 'Accept-Encoding'
+ res.headers.should.not.include('Content-Encoding')
+ res.headers['Content-Length'].should.equal(
+ File.size(DOCROOT + '/cgi/assets/compress_me.html').to_s)
+ end
+
+ should "serve a compressed file" do
+ res = request.get('/cgi/assets/compress_me.html',
+ 'HTTP_ACCEPT_ENCODING' => 'gzip')
+
+ gz = Zlib::GzipReader.new(StringIO.new(res.body))
+ gz.read.should.equal "Hello, Rack!"
+ res.headers['Vary'].should.equal 'Accept-Encoding'
+ res.headers['Content-Encoding'].should.equal 'gzip'
+ res.headers['Content-Type'].should.equal 'text/html'
+ res.headers['Content-Length'].should.equal(
+ File.size(DOCROOT + '/cgi/assets/compress_me.html.gz').to_s)
+ end
+end
Please sign in to comment.
Something went wrong with that request. Please try again.