Join GitHub today
GitHub is home to over 50 million developers working together to host and review code, manage projects, and build software together.Sign up
Response etags to always be weak: Prefixed 'W/' to value returned by Act... #17573
Nice! If we make this more conservative, we can probably get away with sneaking this into 4.2:
This seems like an overall improvement to the situation and a good halfway point. Ideally though, we should also figure out the final API we would like to achieve with this (though I'm not sure if something like that is still appropriate for 4.2 at this time)...
With the current API, I'm not sure what's the best way to achieve point 2, and I'd love to hear ideas
[Sorry about the late response.]
I'm a bit of a noob here, but from what I've seen in the code, our current behavior resembles weak etags more. Even though the etags emitted look strong. I could not find any code that actually creates an etag based off the entire response body. Here's an example to illustrate -
In the classic blog post application, we can write the
And then here's what we see from the browser -
The same happens when using the
I too feel that strong etags are important for cases like
I'm having a lot of cache misses because of this behavior. I'm using nginx as reverse proxy and when a page is requested with
As a quick alternative the etag_matches? method can be changed to strip any
I'm going to try rails_weak_etags middleware to see if it solves my issues.
LGTM. What's missing to get this merged?
I don't think there needs to be a configuration options, because the way etags are calculated is already weak validation and Rack::ETag even weakens it's strong etags (a body digest is considered a strong validator based on RFC 7232 Section 2.1, while determining the etag from arbitrary data is considered a weak validator).
The current problem without this patch is that NGINX weakens strong ETags when it changes the content encoding (gzip). So right now
Another approach would be to consider a weakened etag equivalent to the strong etag sent by action dispatch (but I think sending weak etags as proposed here is the correct approach):
module ActionDispatch module Http module Cache module Request NORMALIZE_ETAG = /^(?:W\/)?\"|\"$/.freeze def if_none_match_etags (if_none_match ? if_none_match.split(/\s*,\s*/) : ).collect do |etag| etag.gsub(NORMALIZE_ETAG, "") end end def etag_matches?(etag) if etag etag = etag.gsub(NORMALIZE_ETAG, "") if_none_match_etags.include?(etag) end end end end end end
I'm currently using the above code as a monkey patch with rails 4.2.4 to fix If-None-Match on NGINX 1.8.
Thanks. Commenting for future Rails 4.2 users on CloudFlare because CF (silently) automatically convert strong ETags to weak ETags by prepending W/ in the header. Googling W/ is pretty ineffective and CloudFlare doesn't document this behaviour so hopefully this comment helps visibility. TLDR use Rails 5 or the rails_weak_etags gem.