Skip to content

Commit

Permalink
Add cache headers to static files served through Rails (mastodon#24120)
Browse files Browse the repository at this point in the history
  • Loading branch information
Gargron authored and Mastodon en masto.es committed Apr 16, 2023
1 parent 6549fea commit 3a08e76
Show file tree
Hide file tree
Showing 5 changed files with 49 additions and 21 deletions.
5 changes: 5 additions & 0 deletions config/application.rb
Expand Up @@ -35,6 +35,7 @@
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'
Expand Down Expand Up @@ -181,6 +182,10 @@ class Application < Rails::Application
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

Expand Down
5 changes: 0 additions & 5 deletions config/environments/development.rb
Expand Up @@ -16,12 +16,7 @@
# 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

Expand Down
12 changes: 1 addition & 11 deletions config/environments/production.rb
Expand Up @@ -19,24 +19,14 @@
# 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?

Expand Down Expand Up @@ -66,7 +56,7 @@

# 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
Expand Down
5 changes: 0 additions & 5 deletions config/environments/test.rb
Expand Up @@ -12,11 +12,6 @@
# 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.
Expand Down
43 changes: 43 additions & 0 deletions lib/public_file_server_middleware.rb
@@ -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

0 comments on commit 3a08e76

Please sign in to comment.