Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add cache headers to static files served through Rails #24120

Merged
merged 1 commit into from Mar 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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
6 changes: 0 additions & 6 deletions config/environments/development.rb
Expand Up @@ -16,15 +16,9 @@
# 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
end

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 = 'X-Sendfile' # for Apache
config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX
Expand Down Expand Up @@ -67,7 +57,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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this change?


# 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