diff options
author | schneems <richard.schneeman@gmail.com> | 2014-08-11 13:29:25 -0500 |
---|---|---|
committer | schneems <richard.schneeman@gmail.com> | 2014-08-20 22:33:06 -0500 |
commit | cfaaacd9763642e91761de54c90669a88d772e5a (patch) | |
tree | ff90fb56588437028462e209cd6b5cf77ae786f0 /actionpack/lib/action_dispatch | |
parent | 2e355fe0c7f0e4b8a3102864191c0be83fa4c12e (diff) | |
download | rails-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.rb | 54 |
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 |