From 96dbeb8608d3eefa3f177d416854c261d16a5aaf Mon Sep 17 00:00:00 2001 From: Sam Date: Fri, 22 May 2015 11:21:16 +1000 Subject: [PATCH] fix stylesheet cache to recover if file is on disk --- app/controllers/stylesheets_controller.rb | 28 +++++++++++++------ app/models/stylesheet_cache.rb | 2 +- lib/sass/discourse_stylesheets.rb | 6 +++- .../stylesheets_controller_spec.rb | 25 +++++++++++++++++ 4 files changed, 50 insertions(+), 11 deletions(-) create mode 100644 spec/controllers/stylesheets_controller_spec.rb diff --git a/app/controllers/stylesheets_controller.rb b/app/controllers/stylesheets_controller.rb index 97b9f2b4984..f346f953db0 100644 --- a/app/controllers/stylesheets_controller.rb +++ b/app/controllers/stylesheets_controller.rb @@ -4,43 +4,53 @@ class StylesheetsController < ApplicationController def show target,digest = params[:name].split("_") - digest_orig = digest - digest = "_" + digest if digest cache_time = request.env["HTTP_IF_MODIFIED_SINCE"] cache_time = Time.rfc2822(cache_time) rescue nil if cache_time query = StylesheetCache.where(target: target) if digest - query = query.where(digest: digest_orig) + query = query.where(digest: digest) else query = query.order('id desc') end + # Security note, safe due to route constraint + underscore_digest = digest ? "_" + digest : "" + location = "#{Rails.root}/#{DiscourseStylesheets::CACHE_PATH}/#{target}#{underscore_digest}.css" + stylesheet_time = query.pluck(:created_at).first + if !stylesheet_time - return render nothing: true, status: 404 + handle_missing_cache(location, target, digest) end if cache_time && stylesheet_time && stylesheet_time <= cache_time return render nothing: true, status: 304 end - # Security note, safe due to route constraint - location = "#{Rails.root}/#{DiscourseStylesheets::CACHE_PATH}/#{target}#{digest}.css" unless File.exist?(location) if current = query.first File.write(location, current.content) else - return render nothing: true, status: 404 + raise Discourse::NotFound end end - response.headers['Last-Modified'] = stylesheet_time.httpdate + response.headers['Last-Modified'] = stylesheet_time.httpdate if stylesheet_time expires_in 1.year, public: true unless Rails.env == "development" send_file(location, disposition: :inline) - end + + protected + + def handle_missing_cache(location, name, digest) + existing = File.read(location) rescue nil + if existing && digest + StylesheetCache.add(name, digest, existing) + end + end + end diff --git a/app/models/stylesheet_cache.rb b/app/models/stylesheet_cache.rb index 331fb136545..76526dd52a9 100644 --- a/app/models/stylesheet_cache.rb +++ b/app/models/stylesheet_cache.rb @@ -1,7 +1,7 @@ class StylesheetCache < ActiveRecord::Base self.table_name = 'stylesheet_cache' - MAX_TO_KEEP = 10 + MAX_TO_KEEP = 50 def self.add(target,digest,content) diff --git a/lib/sass/discourse_stylesheets.rb b/lib/sass/discourse_stylesheets.rb index 46452e6b233..c37ed0791d8 100644 --- a/lib/sass/discourse_stylesheets.rb +++ b/lib/sass/discourse_stylesheets.rb @@ -118,10 +118,14 @@ class DiscourseStylesheets end end - def cache_fullpath + def self.cache_fullpath "#{Rails.root}/#{CACHE_PATH}" end + def cache_fullpath + self.class.cache_fullpath + end + def stylesheet_fullpath "#{cache_fullpath}/#{stylesheet_filename}" end diff --git a/spec/controllers/stylesheets_controller_spec.rb b/spec/controllers/stylesheets_controller_spec.rb new file mode 100644 index 00000000000..c37f6f292a4 --- /dev/null +++ b/spec/controllers/stylesheets_controller_spec.rb @@ -0,0 +1,25 @@ +require 'spec_helper' + +describe StylesheetsController do + + it 'can survive cache miss' do + DiscourseStylesheets.cache.clear + DiscourseStylesheets.stylesheet_link_tag('desktop_rtl') + + StylesheetCache.destroy_all + + # digestless + get :show, name: 'desktop_rtl' + expect(response).to be_success + + # tmp folder destruction and cached + `rm #{DiscourseStylesheets.cache_fullpath}/*` + + get :show, name: 'desktop_rtl' + expect(response).to be_success + + # there is an edge case which is ... disk and db cache is nuked, very unlikely to happen + + end + +end