aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib/action_dispatch
diff options
context:
space:
mode:
authorschneems <richard.schneeman@gmail.com>2014-08-11 13:29:25 -0500
committerschneems <richard.schneeman@gmail.com>2014-08-20 22:33:06 -0500
commitcfaaacd9763642e91761de54c90669a88d772e5a (patch)
treeff90fb56588437028462e209cd6b5cf77ae786f0 /actionpack/lib/action_dispatch
parent2e355fe0c7f0e4b8a3102864191c0be83fa4c12e (diff)
downloadrails-cfaaacd9763642e91761de54c90669a88d772e5a.tar.gz
rails-cfaaacd9763642e91761de54c90669a88d772e5a.tar.bz2
rails-cfaaacd9763642e91761de54c90669a88d772e5a.zip
Enable gzip compression by default
If someone is using ActionDispatch::Static to serve assets and makes it past the `match?` then the file exists on disk and it will be served. This PR adds in logic that checks to see if the file being served is already compressed (via gzip) and on disk, if it is it will be served as long as the client can handle gzip encoding. If not, then a non gzip file will be served. This additional logic slows down an individual asset request but should speed up the consumer experience as compressed files are served and production applications should be delivered with a CDN. This PR allows a CDN to cache a gzip file by setting the `Vary` header appropriately. In net this should speed up a production application that are using Rails as an origin for a CDN. Non-asset request speed is not affected in this PR.
Diffstat (limited to 'actionpack/lib/action_dispatch')
-rw-r--r--actionpack/lib/action_dispatch/middleware/static.rb54
1 files changed, 40 insertions, 14 deletions
diff --git a/actionpack/lib/action_dispatch/middleware/static.rb b/actionpack/lib/action_dispatch/middleware/static.rb
index 25e32cdef8..a3e8126ace 100644
--- a/actionpack/lib/action_dispatch/middleware/static.rb
+++ b/actionpack/lib/action_dispatch/middleware/static.rb
@@ -16,8 +16,9 @@ module ActionDispatch
def initialize(root, cache_control)
@root = root.chomp('/')
@compiled_root = /^#{Regexp.escape(root)}/
- headers = cache_control && { 'Cache-Control' => cache_control }
- @file_server = ::Rack::File.new(@root, headers)
+ headers = {}
+ headers['Cache-Control'] = cache_control if cache_control
+ @file_server = ::Rack::File.new(@root, headers)
end
def match?(path)
@@ -36,23 +37,48 @@ module ActionDispatch
end
def call(env)
- @file_server.call(env)
+ path = env['PATH_INFO']
+ gzip_file_exists = gzip_file_exists?(path)
+ if gzip_file_exists && gzip_encoding_accepted?(env)
+ env['PATH_INFO'] = "#{path}.gz"
+ status, headers, body = @file_server.call(env)
+ headers['Content-Encoding'] = 'gzip'
+ headers['Content-Type'] = content_type(path)
+ else
+ status, headers, body = @file_server.call(env)
+ end
+
+ headers['Vary'] = 'Accept-Encoding' if gzip_file_exists
+ return [status, headers, body]
end
- def ext
- @ext ||= begin
- ext = ::ActionController::Base.default_static_extension
- "{,#{ext},/index#{ext}}"
+ private
+ def ext
+ @ext ||= begin
+ ext = ::ActionController::Base.default_static_extension
+ "{,#{ext},/index#{ext}}"
+ end
end
- end
- def unescape_path(path)
- URI.parser.unescape(path)
- end
+ def unescape_path(path)
+ URI.parser.unescape(path)
+ end
- def escape_glob_chars(path)
- path.gsub(/[*?{}\[\]]/, "\\\\\\&")
- end
+ def escape_glob_chars(path)
+ path.gsub(/[*?{}\[\]]/, "\\\\\\&")
+ end
+
+ def content_type(path)
+ ::Rack::Mime.mime_type(::File.extname(path), 'text/plain')
+ end
+
+ def gzip_encoding_accepted?(env)
+ env['HTTP_ACCEPT_ENCODING'] =~ /\bgzip\b/
+ end
+
+ def gzip_file_exists?(path)
+ File.exist?(File.join(@root, "#{::Rack::Utils.unescape(path)}.gz"))
+ end
end
# This middleware will attempt to return the contents of a file's body from