# encoding: utf-8 require 'classy_assets' require 'rack/file' require 'rack/utils' require 'rack/mime' module Rack class ClassyAssets def initialize(app) @app = app @file_server = ::Rack::File.new(::ClassyAssets.config.asset_public_path, { 'Cache-Control' => 'public, max-age=31536000' }) end def call(env) if %w(GET HEAD).include?(env['REQUEST_METHOD']) and env['PATH_INFO'].start_with?("/#{::ClassyAssets.config.asset_prefix}") request = Rack::Request.new(env) encoding = Rack::Utils.select_best_encoding(%w(gzip identity), request.accept_encoding) if encoding == 'gzip' return serve_gzipped_asset(env) else return serve_asset(env) end end status, headers, body = @app.call(env) body.close if body.respond_to?(:close) [status, headers, body] end private def asset_path_exists?(path) full_path = ::File.join(::ClassyAssets.config.asset_public_path, path) ::File.exists?(full_path) end def serve_gzipped_asset(env) compressed_path = env['PATH_INFO'] + '.gz' if asset_path_exists?(compressed_path) env["PATH_INFO"] = compressed_path status, headers, body = @file_server.call(env) path = env["PATH_INFO"] = env["PATH_INFO"].chomp('.gz') vary = headers["Vary"].to_s.split(",").map { |v| v.strip } unless vary.include?("*") || vary.include?("Accept-Encoding") headers["Vary"] = vary.push("Accept-Encoding").join(",") end headers['Content-Encoding'] = 'gzip' headers['Content-Type'] = Rack::Mime.mime_type(File.extname(path), 'text/plain') headers.delete('Content-Length') if headers.has_key? 'Cache-Control' headers['Cache-Control'] += ', no-transform' unless headers['Cache-Control'].include?('no-transform') else headers['Cache-Control'] = 'no-transform' end else status, headers, body = serve_sprockets_asset(env) end [status, headers, body] end def serve_asset(env) if asset_path_exists?(env['PATH_INFO']) status, headers, body = @file_server.call(env) else status, headers, body = serve_sprockets_asset(env) end [status, headers, body] end def serve_sprockets_asset(env) env["PATH_INFO"].gsub!("/#{::ClassyAssets.config.asset_prefix}", '') ::ClassyAssets.sprockets.call(env) end end end