From 6d30baa28c6f03e5b8584b3542a4fa8a6b35e303 Mon Sep 17 00:00:00 2001 From: Beth Skurrie Date: Mon, 1 Jul 2019 12:36:11 +1000 Subject: [PATCH] feat: add Vary header to avoid browser returning the wrong cached content type for a resource --- lib/pact_broker/app.rb | 2 + lib/rack/pact_broker/add_vary_header.rb | 39 +++++++++++++++++++ ...convert_file_extension_to_accept_header.rb | 2 + 3 files changed, 43 insertions(+) create mode 100644 lib/rack/pact_broker/add_vary_header.rb diff --git a/lib/pact_broker/app.rb b/lib/pact_broker/app.rb index 6420b7179..87fa2221d 100644 --- a/lib/pact_broker/app.rb +++ b/lib/pact_broker/app.rb @@ -15,6 +15,7 @@ require 'rack/pact_broker/no_auth' require 'rack/pact_broker/convert_404_to_hal' require 'rack/pact_broker/reset_thread_data' +require 'rack/pact_broker/add_vary_header' require 'sucker_punch' module PactBroker @@ -151,6 +152,7 @@ def configure_middleware @app_builder.use Rack::PactBroker::ResetThreadData @app_builder.use Rack::PactBroker::StoreBaseURL @app_builder.use Rack::PactBroker::AddPactBrokerVersionHeader + @app_builder.use Rack::PactBroker::AddVaryHeader @app_builder.use Rack::Static, :urls => ["/stylesheets", "/css", "/fonts", "/js", "/javascripts", "/images"], :root => PactBroker.project_root.join("public") @app_builder.use Rack::Static, :urls => ["/favicon.ico"], :root => PactBroker.project_root.join("public/images"), header_rules: [[:all, {'Content-Type' => 'image/x-icon'}]] @app_builder.use Rack::PactBroker::ConvertFileExtensionToAcceptHeader diff --git a/lib/rack/pact_broker/add_vary_header.rb b/lib/rack/pact_broker/add_vary_header.rb new file mode 100644 index 000000000..e94bb8729 --- /dev/null +++ b/lib/rack/pact_broker/add_vary_header.rb @@ -0,0 +1,39 @@ +=begin + + This header should fix the situation where using the back button shows the json/csv instead of the html. + + > Unlike intermediary caches (such as CDNs), browsers typically do not implement the capability to + store multiple variations per URL. The rationale for this is that the things we typically use Vary + for (mainly Accept-Encoding and Accept-Language) do not change frequently within the context of a + single user. Accept-Encoding might (but probably doesn’t) change upon a browser upgrade, and + Accept-Language would most likely only change if you edit your operating system’s language locale + settings. It also happens to be a lot easier to implement Vary in this way, although some specification + authors believe this was a mistake. + + > It’s no great loss most of the time for a browser to store only one variation, but it is important + that we don’t accidentally use a variation that isn’t valid anymore if the “varied on” data does + happen to change. + + > The compromise is to treat Vary as a validator, not a key. Browsers compute cache keys in the normal + way (essentially, using the URL), and then if they score a hit, they check that the request satisfies any + ry rules that are baked into the cached response. If it doesn’t, then the browser treats the request as a + iss on the cache, and it moves on to the next layer of cache or out to the network. When a fresh response + is received, it will then overwrite the cached version, even though it’s technically a different variation. + + https://www.smashingmagazine.com/2017/11/understanding-vary-header/ +=end + +module Rack + module PactBroker + class AddVaryHeader + def initialize app + @app = app + end + + def call(env) + status, headers, body = @app.call(env) + [status, { "Vary" => "Accept" }.merge(headers || {}), body] + end + end + end +end diff --git a/lib/rack/pact_broker/convert_file_extension_to_accept_header.rb b/lib/rack/pact_broker/convert_file_extension_to_accept_header.rb index f2f4b1585..ec3551376 100644 --- a/lib/rack/pact_broker/convert_file_extension_to_accept_header.rb +++ b/lib/rack/pact_broker/convert_file_extension_to_accept_header.rb @@ -3,6 +3,8 @@ module PactBroker # If the HTML and the CSV group resources are both requested by the browser, # Chrome gets confused by the content types, and when you click back, it tries to load the CSV # instead of the HTML page. So we have to give the CSV resource a different URL (.csv) + # Update: this should be fixed by lib/rack/pact_broker/add_vary_header.rb, but may as well + # leave it now! class ConvertFileExtensionToAcceptHeader