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
Strong ETag validators #24387
Strong ETag validators #24387
Conversation
* Introduce `Response#strong_etag=` and `#weak_etag=` and analogous options for `fresh_when` and `stale?`. `Response#etag=` sets a weak ETag. Strong ETags are desirable when you're serving byte-for-byte identical responses that support Range requests, like PDFs or videos (typically done by reproxying the response from a backend storage service). Also desirable when fronted by some CDNs that support strong ETags only, like Akamai. * No longer strips quotes (`"`) from ETag values before comparing them. Quotes are significant, part of the ETag. A quoted ETag and an unquoted one are not the same entity. * Support `If-None-Match: *`. Rarely useful for GET requests; meant to provide some optimistic concurrency control for PUT requests.
The document is written with "only generate weak", but it can also be used to strong etag. Also, add missing entory for rails#24387
The document is written with "only generate weak", but it can also be used to strong etag. Also, add missing entory for rails#24387
@@ -86,12 +101,16 @@ def etag(&etagger) | |||
# | |||
# before_action { fresh_when @article, template: 'widgets/show' } | |||
# | |||
def fresh_when(object = nil, etag: object, last_modified: nil, public: false, template: nil) | |||
def fresh_when(object = nil, etag: nil, weak_etag: nil, strong_etag: nil, last_modified: nil, public: false, template: nil) | |||
weak_etag ||= etag || object unless strong_etag |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hello @jeremy ! I have a question about this change (if you remember… it's almost one year old).
Before this PR, I was able to use fresh_when
to cache a page based solely on last_modified, and completely ignoring the body.
For instance, I could have an action like this:
def index
@sections = Section.all
fresh_when @sections, etag: nil
end
which would render the page if any Section had been updated, or respond with 304 otherwise.
After this PR, I cannot find a way to not set an etag.
Even if I pass etag: nil
or etag: false
, this line:
weak_etag ||= etag || object unless strong_etag
ends up using object
as the value of etag
.
I understand the good intention of this PR: in principle, if your response has changed (and therefore Etag), you want to expire the cache. However, in my case, using last_modified
is enough. If last_modified
didn't change, then I want to serve the cached version without checking the Etag as well.
Am I correct in saying that this approach cannot be taken anymore after this PR?
Introduce
Response#strong_etag=
and#weak_etag=
and analogous optionsfor
fresh_when
andstale?
.Response#etag=
sets a weak ETag.Strong ETags are desirable when you're serving byte-for-byte identical
responses that support Range requests, like PDFs or videos (typically
done by reproxying the response from a backend storage service).
Also desirable when fronted by some CDNs that support strong ETags
only, like Akamai.
No longer strips quotes (
"
) from ETag values before comparing them.Quotes are significant, part of the ETag. A quoted ETag and an unquoted
one are not the same entity.
Support
If-None-Match: *
. Rarely useful for GET requests; meantto provide some optimistic concurrency control for PUT requests.