Reload, reloaded: faster and leaner page reloads
blog.chromium.org
blog.chromium.org
> we found that Chrome would revalidate all resources on pages that were loaded from making a POST request. The Chrome team told us the rationale for this was that POST requests tend to be pages that make a change — like making a purchase or sending an email — and that the user would want to have the most up-to-date page. However, sites like Facebook use POST requests as part of our login process. Every time a user logged in to Facebook the browser ignored its cache and revalidated all the previously downloaded resources. We worked with Chrome product managers and engineers and determined that this behavior was unique to Chrome and unnecessary. After fixing this, Chrome went from having 63% of its requests being conditional to 24% of them being conditional.
And later on, discussing immutable long-cached resources:
> There was some debate about what to do, and we proposed a compromise where resources with a long max-age would never get revalidated, but that for resources with a shorter max-age the old behavior would apply. The Chrome team thought about this and decided to apply the change for all cached resources, not just the long-lived ones. You can read more about their process here [the parent article]. Because of Chrome's blanket approach, all developers and sites are able to see improvement without making any changes themselves.
They say Firefox resolved not to implement it this way, instead adding a new cache-control header, "immutable." https://hacks.mozilla.org/2017/01/using-immutable-caching-to...
So, uh, this means that Chrome and Firefox now have very different caching behavior, by design. :-(
I must say that I prefer Firefox's approach, or even FB's approach where long-lived cache results are handled differently. Refresh's revalidation behavior provides a valuable safety net to ensure that users know how to get a page "back to normal."
Regardless, I wish the Chrome and Firefox team would come to agreement on a proposal, rather than each doing their own thing. That's bad for the web.
So what does this look like in practice? rather than serve a your css as
<link rel="stylesheet" type="text/css" "ref="https://example.com/styles/site.css"/>
you'd instead use something like[2]: <link rel="stylesheet" type="text/css" "ref="sha256:abc123..."/>
And all the resources could be verified for integrity after being downloaded and trivially changed thereafter.For privacy concerns, the url provides the additional feature of sandboxing the content via the origin access controls. As a step 2 addition the urn could still contain the current url style as an optional suffixed parameter, which if provided the browser would use to sandbox that particular hash to that site as a provider of it. Referring to that hash from a site that has not previously provided the data would fail, unless the site is able to either prove that has the data by resending it, or rehashing it some way.
1: I don't mean to be pedantic but a lot of people don't understand that you can take any number of bytes, compute a 256 or 512 bit cryptographic hash for it, and be guaranteed of a longer than the lifetime of the universe level small chance of ever finding any other bytes that produce the same 256 or 512 bit number, even when trying as hard as you can with all the resources you can muster.
2: There are several different ways to do the addressing for the content (magnet uris, IPFS univeral hashes etc). The browser vendors ought to pick one and move on.
The subresource integrity spec supports cases where the developer is able to calculate the hash beforehand
Though it would be nice to somehow have the url self-descriptively assert its purity. Something to the effect of saying `I don't have the content-hash for this now but whatever i return is going to be immutable`, rather than having to muck around in the web-server protocol layer to assert that fact via cache-control: immutable.
I think fundamentally the metadata on whether a particular url is immutable/pure or not, should be self evident, rather than buried in as an implementation detail in the response's http header.
For instance, here are the tags for Bootstrap:
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>So overall I would propose to drop the notion of location all together and just serve items by their integrity hash along with an fallback location which will typically be a classic http[s]:// url.
Ideally in the future I will be able to copy-paste those urn's into my browsers address bar and have them resolve right to the resource which will involve the browser either serving from it's local sha store or using the fallback url.
In the future when some sort of IPFS or other federated resource by sha provider takes hold then the fallback urls will become less and less needed.
To me it's just about making the links themselves be self-descriptive enough to allow them to truly become immutable and then, eventually, more efficiently served.
Discussion of the Firefox approach: https://news.ycombinator.com/item?id=13493407
Usually a reload will solve this issue. It sounds like the Chrome team wanted to validate only the main resource and rely on cached data - isn't this inherently going to break the "reload a broken page" use case? It sounds as if the Chrome team wants to abandon that use case entirely because "the quality of webpages has improved". That may be true - but the quality of some network links hasn't!
What if the resource is corrupt -- say a bit got flipped due to a hardware error. In the old version of reload you would send a conditional request to the server "has this resource been modified since date X". The server would say "no it hasn't" with a 304 (unless the bit flip happened to affect the header and changed the date to a much newer date). Thus a normal reload would cause you to continue to use the invalid resource. The only way to fix this situation is by doing a ctrl+shift+r -- neither Chrome's nor Firefox's approach makes this worse than it was in the past
1: https://developer.mozilla.org/en-US/docs/Web/Security/Subres...
Surely moving from "reload everything" to just "reload the page only" will break some existing use cases.
I suspect, for example, some people use the reload button when a captcha isn't readable, even if the captcha has a little reload button.
It's actually been super annoying to explain to Project Managers - as they often don't see CSS changes due to this change (which actually happened nearly over a month ago).
> It's actually been super annoying to explain to Project Managers - as they often don't see CSS changes due to this change (which actually happened nearly over a month ago).
You are appending a cachebuster to the URL that changes for every release, right?
I'm in a department with a many years outdated CMS. The modern CMS does this after minification. The version I'm stuck with doesn't do cache busting or minification. My department is stuck on the outdated CMS due to our necessary continued support of IE8. So unfortunately no, we're not. We do so manually once a site is in production but it isn't worth the effort to do manually while things are still fast moving and internal. It's much easier to occasionally remind the project manager that they need to do a hard refresh.
For each filetype, set up your webserver such that `filename.[10-digits].css` is handled identically to `filename.css`. In apache, you can do this in .htaccess with a rule that looks something like:
RewriteRule ^(.*)\.[\d]{10}\.(css|js|png)$ $1.$2 [L]
Then generate your links by throwing the file's last modified timestamp into the URL. The net result is that if the file changes, the URL changes, and so the cache no longer applies. It's better than using a "fake" parameter (e.g. file.js?v=2) because using fake parameters suggests that the file is dynamic, causing browsers and proxies to behave differently.