13 ms·
Why Prefetch Is Broken
- slver 5y agoIf the cache is per domain, does that mean CDN-served dependencies like JQuery and React are in fact... useless in terms of cache reuse.
- floo 5y agoYes.
- WayToDoor 5y agoYes. CDNs only offer limited benefits such as lower latency and higher bandwidth.
- SemiNormal 5y agoSo still useful for images and other large files. Not so much with scripts.
- jefftk 5y agoYes. They didn't used to be, but they are now.
- move-on-by 5y agoAs others have already said: Yes, it is useless in terms of cache. Besides it being useless in terms of cache, it also incurs other overhead. Another DNS request, another TCP handshake, another TLS connection. With HTTP 1.1, this might still make sense because you don't get resource pipelining, but with HTTPv2, the extra overhead is simply extra overhead. With HTTPv3, it becomes even less useful to have the domains sharded. Generally speaking, the best use of resource usage with the modern web is to serve everything from the same domain.
- anticristi 5y agoI kind of like how protocol improvements have made the domain an authority, almost like a frontend security boundary.
- eli 5y agoHonestly cache reuse was never as high as anyone hoped. There were so many versions of jQuery and so many different CDNs that very few first time visitors already had the one you wanted.
- Cthulhu_ 5y agoAnd that's fine; CDN benefits are minimal, given how many versions of dependencies are out in the wild, and how the total payload of a website can be reduced by clever packaging and modern data transfer mechanisms. The JS standard library also improved since then, with things like CSS selectors, the Fetch API, and CSS animations being part of the standard library nowadays. I'd argue there's few 'shared' dependencies on websites nowadays.
- r1ch 5y agoUsing a library-provided CDN can be performance-negative now, since you usually need several RTTs for DNS, TCP, TLS before you even get to HTTP. Serving it from your own domain / CDN allows it to be part of an existing HTTP connection.
- kevingadd 5y agoYeah, the security changes here made CDNs go from good to actively bad.
- pornel 5y agoYes. Browsers and protocols have changed, and a lot of past performance best-practices have become actively harmful for performance. A couple of related techniques are also useless: domain sharding and cookieless domains. HTTP/2 multiplexing and header compression made them obsolete, and now they're just an overhead for DNS+TLS, and often break HTTP/2 prioritization. You should be careful with prefetch too. Thanks to preload scanners and HTTP/2 prioritization there are few situations where it is really beneficial. But there are many ways to screw it up and cause unnecessary or double downloads.
- bmn__ 5y agoTo make cacheing efficient again: https://developer.mozilla.org/docs/Web/Security/Subresource_Integrity https://developer.mozilla.org/docs/Web/Security/Subresource_... https://localcdn.org/ https://localcdn.org/
- matsemann 5y agoI don't really understand the issue? If I want to prefetch an image, I'm on the same origin the whole time and this cache segregation doesn't matter.
- bastawhiz 5y agoYeah, his slideshow example doesn't show the problem. Unless each slide was on its own domain, this isn't a problem. It matters for things like Goggle Fonts, but very few folks have multiple domains that share enough of the same assets for this to matter in practice.
- dannyw 5y agoQuestion: Does Google use Google Fonts to track users across the web? Google's FAQ [1] says that it only collects the information needed to serve fonts, but it says the generic Google privacy policy applies. The Google Privacy Policy allows them to use any information it collects for advertising purposes. While Google also states that requests do not contain cookies, Google Chrome will automatically send a high-entropy [3], persistent identifier on all requests to Google properties, and this cannot be disabled (X-client-data) [2]. Google can use this X-client-data, combined with the useragent's IP address, to uniquely identify each Chrome user, without cookies. So, perhaps the privacy statement is more of a sneakily worded non-denial? [1]: https://developers.google.com/fonts/faq?hl=en#what_does_using_the_google_fonts_api_mean_for_the_privacy_of_my_users https://developers.google.com/fonts/faq?hl=en#what_does_usin... [2]: https://github.com/w3ctag/design-reviews/issues/467#issuecomment-581944600 https://github.com/w3ctag/design-reviews/issues/467#issuecom... [3]: A sample: `X-client-data: CIS2yQEIprbJAZjBtskBCKmdygEI8J/KAQjLrsoBCL2wygEI97TKAQiVtcoBCO21ygEYq6TKARjWscoB` - looks very high entropy to me!
- londons_explore 5y agoYou could always ask someone who works on Google Fonts. I did just that. The answer is they don't use the logs for much apart from counting how many people use each font to draw pretty graphs. Doesn't mean that won't change in the future though. But log retention is only a matter of days, so they can't retrospectively change what they do to invade your privacy.
- ZiiS 5y agoIsn't the actual problem with Chrome's behavior and as=document that they still leak? If a.test preloads b.test/i_have_visited_a.html and it is added to b.test's cache.
- londons_explore 5y agoCorrect. as=document reintroduces a data leak between different domains, and therefore isn't viable. The only solution is not to allow cross-origin document preloads. Which is lame because the impact on user experience is reasonably substantial.
- jefftk 5y agoHow is as=document more of a leak than ordinary cross-site navigation?
- kevincox 5y agoBecause you can do this without navigating the user. You are correct that this can be accomplished by redirecting to the tracker site and back but this is 1) detrimental to user experience so not frequently done. 2) Easier to detect and block as the behaviour is suspicious 3) Means that your site breaks if the tracker site is down. This is especially an issue if you want to "register" the session with multiple trackers. With preload you can do this in the background very efficiently.
- jefftk 5y agoHmm, I think you're right, there may be a problem here. Unlike any other request you can trigger on a page in a browser that blocks third-party cookies, if a.test has <link rel=prefetch as=document href=b.test> this will send b.test's first-party cookies. This allows cross-site tracking through link decoration without having to navigate the top-level page.
- blixt 5y agoThe cache segregation is a bit of a nuisance when building sites that uses iframes on different domains to sandbox user content. For example, Framer (where I work) sandboxes each user project on a unique subdomain of framercanvas.com, which is on the public suffix list so that different projects can’t share cookies, localStorage etc. But all resources loaded on these subdomains are always loaded fresh for new projects because of cache segregation, even if it’s the same old files being loaded over and over. I wish there was a way to establish a shared cache between two domains, because we could manually implement a content tunnel between framer.com and the sandbox that sends down cached content with postMessage, so optionally sharing cache doesn’t seem like an additional tracking issue if opted in explicitly.
- torgard 5y agoThat's interesting. Just so I understand it correctly: * The iframe loads resources, e.g. /static/bundle.js and /public/index.css (does this include user-defined resources?). * But due to the iframe being embedded on sub**.framercanvas.com, the cache key includes the subdomain. So all resources are fetched again for all projects?
- atirip 5y agoLoad all resources with fetch(), store to cache by yourself, take the response, clone and transfer into anything that can be sent with postMessage()
- mrblampo 5y agoClever! It would be better for the intended behavior to be supported, though, right?
- jefftk 5y agoSo your setup is: outer.example userN.inner.example shared.example/resource Since, as you say, outer.example could load the shared resources and postMessage them into userN.inner.example, it does seem to me like there should be a way for outer.example and userN.inner.example to opt into letting userN.inner.example use the outer.example cache partition. Have you considered raising a spec issue?
- TazeTSchnitzel 5y agoAre “a.test” and “b.test” meant to represent different domains? The actual syntax used would just be different file paths.
- runxel 5y agoReally hard to understand. I think this should be rewritten to make it more clear.
- ksec 5y agoYes. It should have been Example.com or something like that. Where we instantly knew it was a domain name.
- slver 5y agoYes, different domains.
- kevincox 5y agoOr .example which is a TLD reserved for examples. Different file paths wouldn't cut it because they are same-origin and don't trigger this issue.
- torgard 5y agoThis is quite interesting. I didn't know this was a thing. A primary issue, as I see it, is caching of third-party assets (as dmkil posted elsewhere, think jQuery, Google Fonts, Facebook Pixel, etc). Could this not be solved using the Cache-Control header, or maybe some HTML attribute variation of this? Maybe something like: <!-- Use a site-specific cache for its stylesheet, default behavior --> <link rel=spreadsheet href=index.css cache-key="private"> <!-- Use a global cache for jQuery --> <script src="https://code.jquery.com/jquery-3.6.0.slim.min.js" integrity="sha256-u7e5khyithlIdTpu22PHhENmPcRdFiHRjhAuHcs05RI=" crossorigin="anonymous" cache-key="public" ></script>
- ktpsns 5y agoYour cache-key idea infiltrates the overall idea with third-party access. As a site owner who wants to place Ads I just use your script notation to include the ad and then leak data again...
- torgard 5y agoAh yes, of course. I was thinking with a perspective of a user who has full control of the site, as they are the owner too. The cache-key idea would only work if the user themselves could specify it for every resource.
- andrejguran 5y agoI don't understand the problem here! Prefetch loads additional data while you're not doing anything. The whole argument is that prefetch doesn't respect caching??? Those are two different concepts. While I am looking at slide N I don't care if slide N+1 image is loaded fresh or from a cache. Am I missing something here?
- skymt 5y agoYou are missing something, but I wish people hadn't down-voted you for asking an honest question. The problem described in the blog post is that prefetch loads the resource into cache, which when combined with per-site cache segmentation means that it's ambiguous which cache a resource should be loaded into when it's prefetched across sites.
- danjordan 5y agoIt was a surprise to me that browsers partition their cache now. I think Safari has done it since 2013! When I found out I wrote a blog post about the HTTP Cache partitioning and hosting jQuery, or any library, from a CDN. https://www.danjordan.dev/posts/should-i-host-jquery-from-a-cdn/ https://www.danjordan.dev/posts/should-i-host-jquery-from-a-...
- labster 5y agoPrefetching is a cool idea but a lot of us can’t actually use it. I tried implementing prefetch in a personal project only to find out uBlock Origin is disabling it. Apparently prefetched resources aren’t filtered by extensions, which kind of defeats tracking protection. So I can’t even use it for my own project, as I’d rather avoid the trackers. I assume many people are using the same default setting here.
- kevincox 5y ago> I tried implementing prefetch in a personal project only to find out uBlock Origin is disabling it. That seems fine to me. Implement it and if the users don't want it then it doesn't occur. You should still code as if it works. > Apparently prefetched resources aren’t filtered by extensions This sounds like a browser bug. It should probably be raised against the browsers. > as I’d rather avoid the trackers. Again, this is just a result of the browser bug. I see no reason to throw away a nice declarative prefetch simply because browsers forgot to allow filtering.
- willis936 5y ago>That seems fine to me. Implement it and if the users don't want it then it doesn't occur. You should still code as if it works. Please correct me if I'm misinterpreting this statement. Are you saying it is acceptable if the code breaks if prefetch fails?
- ninjapenguin54 5y agoHow would the absence of a prefetch break something? Isn't this just a performance optimization? I take the original statement to mean that worse case scenario is extra time to load.
- kevincox 5y agoYes, that is what I meant. You may as well include the prefetch. And if the browser (or the user) doesn't want the prefetch they just get a slower load. If the user enables them the get the snappier experience.
- shuringai 5y agoi would rather wait even seconds for a page to load than having my cache bruteforced
- xallarap 5y agoThat aside it's a terrible name because it looks like preftech. If it's just caching they why not keep the ass tight?
- failwhaleshark 5y agoIsn't it a best practice to white screen / "loading" until everything important is loaded? How does one detect when everything is loaded? I've seen some websites break when UI interaction occurs before all js are loaded.