class HerokuRailsDeflate::ServeZippedAssets

Public Class Methods

new(app, root, asset_prefix, cache_control=nil) click to toggle source

Params:

root: the public directory
asset_prefix: config.assets.prefix
cache_control: config.static_cache_control
# File lib/heroku_rails_deflate/serve_zipped_assets.rb, line 13
def initialize(app, root, asset_prefix, cache_control=nil)
  @app = app
  @asset_prefix = asset_prefix.chomp('/') + '/'
  @file_handler = ActionDispatch::FileHandler.new(root, cache_control)
end

Public Instance Methods

call(env) click to toggle source
# File lib/heroku_rails_deflate/serve_zipped_assets.rb, line 19
def call(env)
  # Only process get requests
  if env['REQUEST_METHOD'] == 'GET'
    request = Rack::Request.new(env)

    # See if client accepts gzip encoding
    if Rack::Utils.select_best_encoding(%w(gzip identity), request.accept_encoding) == 'gzip'
      # Check if compressed version exists in assets directory
      compressed_path = env['PATH_INFO'] + '.gz'
      if compressed_path.start_with?(@asset_prefix) && (match = @file_handler.match?(compressed_path))
        # Use FileHandler to serve up the gzipped file, then strip the .gz suffix
        path = env["PATH_INFO"] = match
        status, headers, body = @file_handler.call(env)
        path = env["PATH_INFO"] = env["PATH_INFO"].chomp('.gz')

        # Set the Vary HTTP header.
        vary = headers["Vary"].to_s.split(",").map(&:strip)
        unless vary.include?("*") || vary.include?("Accept-Encoding")
          headers["Vary"] = vary.push("Accept-Encoding").join(",")
        end

        # Add encoding and type
        headers['Content-Encoding'] = 'gzip'
        headers['Content-Type'] = Rack::Mime.mime_type(File.extname(path), 'text/plain')

        # Update cache-control to add directive telling Rack::Deflate to leave it alone.
        cache_control = headers['Cache-Control'].try(:to_s).try(:downcase)
        if cache_control.nil?
          headers['Cache-Control'] = 'no-transform'
        elsif !cache_control.include?('no-transform')
          headers['Cache-Control'] += ', no-transform'
        end

        body.close if body.respond_to?(:close)
        return [status, headers, body]
      end
    end
  end

  @app.call(env)
end