-
Notifications
You must be signed in to change notification settings - Fork 126
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
Rack::Cache swallows If-None-Match and If-Modified-Since #24
Comments
Hmm. That's a tough one. Just so I'm clear, when you say "private caching" you mean setting the That seems valid to me. I'll have to think about this a little. The reason we remove conditional GET request headers is because we always want content from upstream if we don't already have the response in our cache, so that we can serve subsequent conditional requests without making additional upstream requests. That falls down in this case and I'm not sure how to get around it. We could store that a previous request for the same URL returned a private response but that's a pretty big change. Let me do some research. It'd be great if clients sent a |
Yes exactly, by private caching I mean "Cache-Control: private" to disallow shared caches to store the response. I've been thinking about the problem and I think maybe the issue is in the assumption that the cache needs to fetch the full content if the content is not already in the cache. Let's say the cache does not contain anything for a given request (etag/url combination). The cache would then hit the backend at the url passing the etag. Now two things can happen:
Does this sound like a solution? |
That's interesting. It would only be valid for the amount of time given in the cache control Implementing this is probably non-trivial. I'm not against just letting conditional requests pass through and bypassing any cache storage for now. |
Indeed. That's identical to the current situation in which the cache will need to hit the backend on each request if there's no expiration in the response.
Cool. I might take a stab at it when I get some time. I'll close this for now and get back to you if I get an implementation working. |
Was wondering if this issue could be opened back up (or a new issue created) as this is causing a problem for Rails apps. In Rails 3.1 rack-cache is enabled by default (from what I can tell). This means that http://apidock.com/rails/ActionController/ConditionalGet/stale%3F doesn't work like it is supposed to. Since the headers are removed Rails never has a chance to skip the expensive processing contained inside the if statement. It also renders the template which may be expensive as well. Even though a 304 is returned correctly Rails still did all the work (making the stale? useless). I really don't complete understand this all but the swallowing of these headers is interfering with stale? In addition this behavior is un-expected. I am getting headers zapped and the fact that rack-cache was the one doing it made it VERY hard to track down. What if other headers can do useful stuff with these headers. Seems to violate principal of least surprise. Just my two cents and notes. I still bow down before the gods of programming that put together these wonderful frameworks. :) |
Hmm. I think I see what you're saying. One thing to note is that The only case where the IMS/INM headers are removed is when rack-cache does not have a version of the response in its cache, which should only be on the first request for each resource. Further, rack-cache handles the same kind of The following may be helpful for getting your ahead around some of this behavior: http://tomayko.com/writings/things-caches-do It's about HTTP reverse proxy caches in general but describes rack-cache's behavior exactly. |
Two things:
This stale? functionality worked great prior to rack-cache being added to Rails 3.1. But after rack-cache was added stale? stale stopped working properly. Feel free to correct my understanding here. But my experience is that upgrading to Rails 3.1 made it end up inside the stale? block on EVERY request (even though a 304 goes back after the first response). I can get around this by saying :public => true. But now my lack of understand has me not sure if my stale? check is being performed (hence a database update could cause a page change but the browser may not see it). |
I'm not 100% sure how the :public flag in Rails effects things (does it just set
I'm confused how it can both go inside the |
I think a small example that reproduces this would be the most useful thing here. It's possible there's a bug somewhere or something changed in Rails to cause rack-cache validations to not kick in. What you're describing is definitely not intended behavior. |
According to the documentation I linked in my first post that is exactly what it does.
That is exactly the behavior I am getting. Every request is sent onto Rails (I guess since it is private it doesn't keep it in it's cache?). Then rails not seeing the If-Modified-Since header returns "true" on stale? causing extra processing, template rendering and returns status 200. But the status I get back in browser (according to Chrome) is 304. I assumed Rack was seeing the content didn't change and sent back a 304? |
Interesting. Okay, I think I should be able to reproduce that. Thanks. |
OK, I have have a small example. This is a factory rails app created via the following:
You will see every request goes inside the if statement even though the action indicates the page has not been modified since the epoch! Also Rails returns status 200 while the browser gets 304. |
Thanks so much for that. |
I was able to recreate the issue locally. It definitely looks like it's due to the |
This should be better now. More info: |
It seems Rack::Cache will swallow If-None-Match and If-Modified-Since headers. This seems to be a problem if I want to use Rack::Cache but have parts of my application that only allows private caching. In this case private caching will not reduce the strain on my server.
I've made a fresh Rails3 app and added Rack::Cache.
I'm calling my application with the following command:
And this is what I'm seeing in the log:
After adding Rack::Cache to application.rb and restarting my server this is what I get with the same curl command:
In both cases I do get a 304 back from the server as reported by curl - I'm guessing that might be due to Rack::ConditionalGet though.
The text was updated successfully, but these errors were encountered: