-
Notifications
You must be signed in to change notification settings - Fork 21.4k
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
Implement 'no_store' HTTP cache directive #40324
Conversation
ef076f0
to
617e7a0
Compare
8d76db4
to
d46b250
Compare
Can you add a CHANGELOG entry for the new method added? Also please squash all commits in one. |
d46b250
to
7edcee4
Compare
7edcee4
to
d646315
Compare
@rafaelfranca done. (ps: if anyone's wondering why @rails-bot added "activesupport" label - I updated wrong changelog on previous commit) |
c73c4ca
to
77548fb
Compare
33bb8d9
to
2a2fcb5
Compare
2a2fcb5
to
0bd9812
Compare
0bd9812
to
37cc4a1
Compare
8b89f26
to
1687da0
Compare
Any chance this could be reviewed before next minor release cycle? 🙂 |
1687da0
to
6e128dc
Compare
fb61083
to
8ca1be8
Compare
8ca1be8
to
6f0c550
Compare
@tadas-s Would you mind rebasing this? 🙇 |
6f0c550
to
9fb228a
Compare
Summary ======= Currently there is no way to set "Cache-Control: no-store" header using built-in cache control methods ("expires_now"/"expires_in"/etc..). One of the [top StackOverflow][1] answers currently suggests putting it directly into header set. Unfortunately, it cannot later be overridden in specific/individual actions by calling say 'expires_in 5.minutes'. Resulting header in that case is stays the same, i.e. 'Cache-Control: no-store'. This: 1. Adds the 'no_store' method to set "Cache-Control: no-store" header. 2. Changes cache control "merge and normalize" code so default "no-store" directive can be overridden using built in cache control methods mentioned above. What's the use of it -------------------- Couple examples: * To [prevent rendering stale content][3] if browser return button is used ('expires_now' does not help). * To prevent browser disk cache being used. In some situations it's considered a [privacy/security risk][4]. Other Information ================= Mozilla developer docs for [Cache-Control][2] header. [1]: https://stackoverflow.com/questions/10744169/rails-set-no-cache-method-cannot-disable-browser-caching-in-safari-and-opera [2]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control [3]: https://engineering.mixmax.com/blog/chrome-back-button-cache-no-store/ [4]: https://portswigger.net/kb/issues/00700100_cacheable-https-response
9fb228a
to
07da734
Compare
@zzak rebased. |
@tadas-s I'm looking into a failing tests on the GitHub test suite. It seems this change might have introduced a change which causes the Cache-Control headers to be replaced when the controller's action uses
# frozen_string_literal: true
require "bundler/inline"
gemfile(true) do
source "https://rubygems.org"
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
gem "byebug"
gem "rails", github: "rails/rails", branch: "main"
end
require "byebug"
require "action_controller/railtie"
class TestApp < Rails::Application
config.root = __dir__
config.hosts << "example.org"
secrets.secret_key_base = "secret_key_base"
config.logger = Logger.new($stdout)
Rails.logger = config.logger
routes.draw do
get "/" => "test#index"
end
end
class TestController < ActionController::Base
include Rails.application.routes.url_helpers
def index
headers["Cache-Control"] = "no-cache, no-store"
send_data("foo\r\n", filename: "foobar.txt")
end
end
require "minitest/autorun"
require "rack/test"
class BugTest < Minitest::Test
include Rack::Test::Methods
def test_returns_success
get "/"
assert last_response.ok?
assert_equal "no-store", last_response.headers["Cache-Control"]
end
private
def app
Rails.application
end
end
I'm happy to create a new issue for this if you think this is unintended behavior. A workaround here could be to explicitly set the headers with this new |
Oh this is a fun one. So yes, However.. I assumed that Anyway, I'm still looking at this. |
I'm also wondering if that IE 6.0 hack is still relevant at all 😅 |
Using github search I even found code like this: https://github.com/gitlabhq/gitlabhq/blob/master/app/controllers/concerns/sends_blob.rb#L32-L45 .. Do not think this is a documented way to handle response caching headers. |
@tadas-s Do you want to send a PR? 🙇 |
@zzak will do. I'm still playing around this + want to test with IE8 (lowest currently available IE vm I can get my hands on..). Just in case.. |
I'm curious about this and I'm honestly not 100% sure what the right approach is here. While the Mozilla docs specify As a similar example https://github.com/gitlabhq/gitlabhq/blob/21e08b6197f192c983f8527f4bba1f2aaec8abf2/lib/gitlab/no_cache_headers.rb sets
On another note, I also want to confirm that setting the Cache-Control header is not going to be the proper approach to controlling the values in the header? It almost seems to me like we want a more flexible method for setting these values if we're going to have specific methods like |
IE 6-7-8 has bug when 'Cache-Control: no-cache' head would break file download. It's been fixed in IE9 (which is also ancient and barely used version). Some extra details [here][1] and [here][2]. The way this fix is implemented clashes with what's been done in PR rails#40324. By adding ':public' key to cache control header set it wipes default headers. Since IE 6-7-8 are ancient browsers - let's just get rid of this hack. [1]: https://stackoverflow.com/q/9766639/843067 [2]: https://stackoverflow.com/q/3415370/843067
This is only my opinion, I'm not a Rails maintainer or anything: setting caching headers via Rails provided APIs like |
Hum, this broke our test suite as well. In a controller we have a before_filter with: def configure_cache_control
response.cache_control = 'no-store'
end And this change clears it and replace it with |
@casperisfine any chance you could try re-writing this bit of code into: def configure_cache_control
no_store
end That should do the trick. |
Yeah |
Is there a way to set |
See this section: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#directives And specifically:
(emphasis mine) I understand it's client (i.e. browser side thing) and hence not applicable for Rails/server side. |
@645383 if you could describe what you're trying to solve in bit more detail, myself or someone else reading this may be able to help. |
Sorry, the question is not related to this PR. There are another PRs allow for only no-store in cache-control header and Allow 'private, no-store' Cache-Control header. |
Missed this part |
I tried starting conversation in rubyonrails-core but haven't really got much feedback from there.
Summary
Currently there is no way to set
Cache-Control: no-store
header usingbuilt-in cache control methods (
expires_now
/expires_in
/etc..). One ofthe top StackOverflow answers currently suggests putting it directly
into header set.
Unfortunately, it cannot later be overridden in specific/individual actions by
calling say
expires_in 5.minutes
. Resulting header in that case isstays the same, i.e.
Cache-Control: no-store
.This:
no_store
method to setCache-Control: no-store
header.no-store
directive can be overridden using built in cache control methods mentioned
above.
What's the use of it
Couple examples:
(
expires_now
does not help).a privacy/security risk.
Naming it
I'm open for ideas. Couple random suggestions:
no_store
http_cache_no_store
Other Information
openmerged PR allow for only no-store in cache-control header #39461