~cytrogen/masto-fe

f0e727f958cd9428b2c56a3c6a65bbbf176bfa0d — Eugen Rochko 3 years ago be488ad
Add cache headers to static files served through Rails (#24120)

M config/application.rb => config/application.rb +5 -0
@@ 35,6 35,7 @@ require_relative '../lib/terrapin/multi_pipe_extensions'
require_relative '../lib/mastodon/snowflake'
require_relative '../lib/mastodon/version'
require_relative '../lib/mastodon/rack_middleware'
require_relative '../lib/public_file_server_middleware'
require_relative '../lib/devise/two_factor_ldap_authenticatable'
require_relative '../lib/devise/two_factor_pam_authenticatable'
require_relative '../lib/chewy/strategy/mastodon'


@@ 181,6 182,10 @@ module Mastodon
    config.active_job.queue_adapter = :sidekiq
    config.action_mailer.deliver_later_queue_name = 'mailers'

    # We use our own middleware for this
    config.public_file_server.enabled = false

    config.middleware.use PublicFileServerMiddleware if Rails.env.development? || ENV['RAILS_SERVE_STATIC_FILES'] == 'true'
    config.middleware.use Rack::Attack
    config.middleware.use Mastodon::RackMiddleware


M config/environments/development.rb => config/environments/development.rb +0 -5
@@ 16,12 16,7 @@ Rails.application.configure do
  # Run rails dev:cache to toggle caching.
  if Rails.root.join('tmp/caching-dev.txt').exist?
    config.action_controller.perform_caching = true

    config.cache_store = :redis_cache_store, REDIS_CACHE_PARAMS

    config.public_file_server.headers = {
      'Cache-Control' => "public, max-age=#{2.days.to_i}",
    }
  else
    config.action_controller.perform_caching = false
    config.cache_store = :null_store

M config/environments/production.rb => config/environments/production.rb +1 -11
@@ 19,24 19,14 @@ Rails.application.configure do
  # or in config/master.key. This key is used to decrypt credentials (and other encrypted files).
  # config.require_master_key = true

  # Disable serving static files from the `/public` folder by default since
  # Apache or NGINX already handles this.
  config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present?

  ActiveSupport::Logger.new(STDOUT).tap do |logger|
    logger.formatter = config.log_formatter
    config.logger = ActiveSupport::TaggedLogging.new(logger)
  end

  # Compress JavaScripts and CSS.
  # config.assets.js_compressor = Uglifier.new(mangle: false)
  # config.assets.css_compressor = :sass

  # Do not fallback to assets pipeline if a precompiled asset is missed.
  config.assets.compile = false

  # `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb

  # Specifies the header that your server uses for sending files.
  config.action_dispatch.x_sendfile_header = ENV['SENDFILE_HEADER'] if ENV['SENDFILE_HEADER'].present?



@@ 66,7 56,7 @@ Rails.application.configure do

  # Enable locale fallbacks for I18n (makes lookups for any locale fall back to
  # English when a translation cannot be found).
  config.i18n.fallbacks = [:en]
  config.i18n.fallbacks = true

  # Send deprecation notices to registered listeners.
  config.active_support.deprecation = :notify

M config/environments/test.rb => config/environments/test.rb +0 -5
@@ 12,11 12,6 @@ Rails.application.configure do
  # preloads Rails for running tests, you may have to set it to true.
  config.eager_load = false

  # Configure public file server for tests with Cache-Control for performance.
  config.public_file_server.enabled = true
  config.public_file_server.headers = {
    'Cache-Control' => "public, max-age=#{1.hour.to_i}"
  }
  config.assets.digest = false

  # Show full error reports and disable caching.

A lib/public_file_server_middleware.rb => lib/public_file_server_middleware.rb +43 -0
@@ 0,0 1,43 @@
# frozen_string_literal: true

require 'action_dispatch/middleware/static'

class PublicFileServerMiddleware
  SERVICE_WORKER_TTL = 7.days.to_i
  CACHE_TTL          = 28.days.to_i

  def initialize(app)
    @app = app
    @file_handler = ActionDispatch::FileHandler.new(Rails.application.paths['public'].first)
  end

  def call(env)
    file = @file_handler.attempt(env)

    # If the request is not a static file, move on!
    return @app.call(env) if file.nil?

    status, headers, response = file

    # Set cache headers on static files. Some paths require different cache headers
    headers['Cache-Control'] = begin
      request_path = env['REQUEST_PATH']

      if request_path.start_with?('/sw.js')
        "public, max-age=#{SERVICE_WORKER_TTL}, must-revalidate"
      elsif request_path.start_with?(paperclip_root_url)
        "public, max-age=#{CACHE_TTL}, immutable"
      else
        "public, max-age=#{CACHE_TTL}, must-revalidate"
      end
    end

    [status, headers, response]
  end

  private

  def paperclip_root_url
    ENV.fetch('PAPERCLIP_ROOT_URL', '/system')
  end
end