How does one detect a browser’s cache settings either client side or server side (ASP.NET). Basically trying detect if the users browser has caching on or off. If it's off, I'd like to either redirect them to a page with error message to tell them to turn it on. Is this possible?
You can't reliably detect cache settings as this information is not passed on from the browser.
If resources that should be cached are being requested repeatedly from the browser, this may be an indication that caching is turned off, but that might not be the case.
As for wanting to redirect to an error page - some browsers and environments simply do not have caching, do you want to penalize these users?
Caching is a mechanism to reduce load by reducing the number of requests, don't use it for anything else.
A browser doesn't send out its cache setting to the server.
Maybe you are trying to make some of your page components (images, scripts, etc.) load / interact smoother? If it is, maybe you could try to optimize your page (e.g. sprite, minimized JavaScript) so you don't have to worry too much whether the browser decides to cache your page.
Also, in general, rather than redirecting to a different page, you might also consider simply showing a message on the same page (i.e. 1 less HTTP request).
Related
First, I found some resources online here and here saying about the same thing:
For a normal/soft reload, the browser will re-validate the cache, checking to see if the files are modified.
I tested it on Chrome. I have a webpage index.html which loads a few javascript files in the end of body. When hitting the refresh button (soft/normal), from the network panel I saw index.html was 304 Not Modified, which was good. However, all the javascript files were loaded from memory cache with status code 200. No revalidation!
Then I tried modifying one of the javascript files. Did the soft reload. And guess what? That file was still loaded from memory cache!
Why does Chrome do this? Doesn't that defeat the purpose of the refresh button?
Here is more information about Chrome's memory cache.
This is a relatively new behaviour which was introduced in 2017 by Chrome browser.
The well-known behaviour of browsers is to revalidate cached resource when the user refreshes the page (either by using CTRL+R combination or dedicated refresh button) by sending If-Modified-Since or If-None-Match header. It works for all resources obtained by GET request: stylesheets, scripts, htmls etc. This leads to tons of HTTP requests that in the majority of cases end with 304 Not Modifiedresponses.
The most popular websites are the ones with constantly changing content, so their users tend to refresh them habitually to get the latest news, tweets, videos and posts. It's not hard to imagine how many unnecessary requests were made every second and as it is said that the best request is the one never made, Facebook decided to address this problem and asked Chrome and Firefox to find a solution together.
Chrome came up with the described solution.
Instead of invalidating each subresource, it only checks if the HTML document changed. If it didn't, it means that it's very likely that everything else also wasn't modified, so it's returned from browser's cache. This works best when each resource has content addressed URL; for example, URL contains a hash of the content of the file. Users can always overcome this behaviour by performing a hard refresh.
Firefox's solution gives more control to developers, and it's on a good way to be implemented by all browser vendors. That is the new Cache-control directive: immutable.
You can find more information about it here: https://developer.mozilla.org/pl/docs/Web/HTTP/Headers/Cache-Control#Revalidation_and_reloading
Resources:
Facebook's article about the motivation behind proposed change, numbers, comparisons: https://code.fb.com/web/this-browser-tweak-saved-60-of-requests-to-facebook/?utm_source=codedot_rss_feed
Chromium team introducing new behaviour: https://blog.chromium.org/2017/01/reload-reloaded-faster-and-leaner-page_26.html
Browser caches are a little more complex than simple 200 and 304s than they once were and pay attention to server side directives in headers to tell them how to handle caching for each specific site.
We can adjust the browser caching profiles using various headers (such as Cache-Control) by specifically setting the time before expires you can tell a browser to use the local copy instead of requesting a new fresh copy, these can be quite aggressive in the cases of content you really don't want changed (i.e a companies logo). By doing something like Cache-Control: public, max-age=31536000
Additionally you can also set the Expires header which will allow you to almost do the same as Cache-Control but with a little less control. It just sets the amount of time to pass before the browser considers a asset stale and re-requests. Although with a re-request we could still get a cached result if the not modified response code is sent back from the server.
A lot of web servers have settings enabled to allow more aggressive caching of certain asset files (js, images, css) but less aggressive caching of content files.
Is it possible to get around the security and mimick either a full-browser or mobile browser within a webpage?
I had an idea to set the HTML manually, using an AJAX/XMLHttpRequest ("Get" request)
document.querySelector('#myiframe').contentWindow.document.write("<html><body>Hello
world</body></html>");
(from How to set HTML content into an iframe)
Can anyone verify this is possible? I'm guessing you would lose relevant site date (cookies, cache, etc)
Is it possible to get around the security
Yes, many browsers let you start them in a security-off mode, e.g. on chrome you run the program with the --disable-web-security flag. However, you should never ask a client to do this.
An alternative way would be to write a Java applet, or some other third-party plugin, which fetches the resources you want and then passes it over to the browser with your favourite method, from which you can use JavaScript on the data as desired. This method would lose things like cookies, and might be exploitable so I wouldn't recommend it.
mimick either a full-browser or mobile browser within a webpage?
Finally, if you don't mind the "URL bar" displaying the wrong thing when a user navigates, you could just use the default behaviour. This method is totally acceptable and doesn't circumvent any security.
I am building a web application in Node.js, and using Socket.IO to handle data transfer between my client and server sides.
The core piece of my web application is a content feed. My client-side Javascript emits a Socket.IO call for the contents of the newsfeed. Once the response comes back from the server, it populates the feed on the webpage using JQuery.
My issue is that Socket.IO doesn't cause the browser's page loading indicator (for Chrome, this is a spinning wheel in the webpage's tab) to show. I want it to show. Without this loading indicator, my webpage looks like it's finished loading when it really hasn't (the feed hasn't been populated yet).
What is the proper solution to this problem? Thank you in advance!
There is no proper answer per se: browser vendors have different rationales for why certain activities would and would not show "loading" states: A good rundown here.
In general, ajax-like requests (things asynchronous to actual full page loads) should probably NOT show loading indicators by default, as busy states indicate to users that the browser is slow/busy, and we use ajax requests for all sorts of background tasks. There are, of course, times when a developer would want to show these indicators (form submission, single page apps that download subsequent pages via ajax: times when we want to convey to the user that something major is happening and that they SHOULD wait for it to complete) but we don't have a lot of control over forcing that to happen when it comes to async requests. The only real way to "fake" it on some browsers is to load content in an iframe: some modern browsers do trigger the "busy" state in that case.
With Websockets, most vendors have, probably quite reasonably, applied the same logic as ajax requests: there are a lot of operations you'd want to do with websockets that can happen without a user actually initiating them directly, so they shouldn't trigger that "browser is seriously busy, hold on a second" feel. And, like with ajax, there's sadly no api I know of for countermanding that design decision.
The iframe solution is limited: it works in some browsers but not all (notably, it's ignored in all major mobile browsers). And doing it crudely (i.e. creating a hidden iframe for when you want it to trigger the load indicators and removing it when you want to cancel them) has costs: you basically need to hit a resource that is designed to "stall" (like a php page that just runs sleep(10000) and so keeps the connection open). That's both weighty (extra http request just to trigger an effect) and also ties up some server with keeping open connections that are essentially not doing anything. That probably won't scale, particularly if that server is the same one hosting your app.
You're probably instead stuck with coding a custom loading indicator (spinner, fake progress bar fixed at the top of the screen). It's not satisfying, but it's the only thing guaranteed to communicate some of what you want to users. I have a solution for jQuery's ajax that exploits the iframe approach (Noisy JSON) that you could potentially reproduce as a plugin for socket.io, but if you're using websockets, that basically means falling back to ajax-style communication for requests. And you're still out of luck on Safari, mobile, and newer IEs.
We've identified that full browser caches are the cause of a problem on our extranet. It only affects a small number of our users, but we'd like to alert them to the problem and give them some guidance on how to fix the problem for themselves.
We'd like to use a similar system to the one which GMail uses. When it detects that your browser's cache is full is not behaving as it should, it shows a warning message telling users that their cache is full and that it may cause problems with GMail, along with a link to a Gmail Help page on clearing your browser's cache.
Does anyone know if there any resources out there, or examples of how to use JavaScript to detect that the browser's cache is full behaving badly?
Thanks.
Clarification: What we're actually trying to detect, I suppose, is not whether or not the cache is full, but rather whether a script, which we have configured server-side to be stored in the cache, is being re-requested from the server - in such a way that the browser is behaving strangely, or as if its cache is not behaving as it should.
Further Clarification: Thank you all for the updates on caching. Our scripts are being sent with the correct headers, and we're only seeing this problem in IE6 and IE7 - Mozilla and WebKit browsers seem to be unaffected - but I'm still not sure on how exactly we'd go about using JavaScript and/or XmlHttpRequest to check to see whether or not an object was retrieved from the cache, thus letting us check whether the cache is behaving badly.
The browser's cache will not cause problems if it is full... with a few minor notes.
If the browser cache is full, the browser simply has to download fresh content vs. pulling it from its local cache. (e.g. is slower)
If the browser cache contains invalid data (e.g. an old copy of a JavaScript file) then yes, you may encounter issues. (not because the cache is full, but because you didn't serve up a fresh file for the user (Google for: expires headers and how to alter the URL path to your files when you make script changes to ensure you "break" the cache))
In Internet Explorer, when you push a download file (e.g. an Excel spreadsheet) to the user it must go into the cache to work (an IE bug) - I'm not sure if the file is bigger than the users' total cache, if that causes issues with the file being stored, and therefore loaded (Stackers pls feel free to confirm if this one way or another)
Update:
Based on your clarification, you need to ensure that any script you send to the client is appropriately cached... which means:
Change the URL to your scripts when you want a new version to be downloaded (e.g.)
http://example.com/scripts/latestThing.js?ver=3425
where the "ver" is pulled from your versioning system to ensure you always force the browser to download a fresh copy any time you change your script.
Once you are sure that the URL changes, you can send cache headers that tell the browser to cache the files for a very long time (e.g. your JS Library files (e.g. jQuery) likely don't change every hour, day, week or even month)
This will probably not work as is. But its just an idea:
var img = new Image();
(new Image).src = "imageWithFarFutures.png";
window.onload = function(){
document.getElementById("someIframe").src = "imageWithFarFutures.png";
// NOW if the server DOES get a FRESH request for "imageWithFarFutures.png"
// wouldn't it mean that the browser has kicked it out of its cache?
};
Consider sending a header to have your application never cache your content and to have it expire immediately.
I understand that there is no way to kill the iframe breaker... However, I was wondering, is there a way to gracefully handling it.
So far, I managed to detect it before exiting, using <body onunload="function();">. I was wondering whether it is possible to prevent it from loading the iframe or force it to open in the new window, etc.
Cheers,
Mickey
In fact, you can actually do what you really want to do, which is bust the iframe buster. The technique lets you use onbeforeunload to switch the page back to yours, but indirectly, since the browsers are too smart to let you set the URL in onbeforeunload. So instead, onbeforeunload sets an indicator variable to mark that the URL has changed, and you periodically poll that variable using a setInterval routine established when your page loads. As long as you're polling fast enough to catch the variable change, you can jump in and change the page's URL yourself. The trick is to change it to a page that returns a 204, a special status which tells the browser to leave the current page alone.
That said, this is a cat-and-mouse game. Check out Jeff Attwood's StackOverflow question on this, where he asks how to bust the above technique. Web pages can bust the buster buster by beating the poll interval; basically, they set the URL to point to a tiny page, and one that has already been cached. As soon as the URL changes to that page, it will load faster than the poll routine can jump in and notice that the indicator variable has changed.
It's not easy to prevent loading the frame in the first place. If you really wanted, you could have your server download the page and parse the Javascript to see if the iframe-busting technique is present. However, short of emulating a browser, you can only rely on basic pattern-matching and it would be easy for a page to bypass that. (e.g. use top["l"+"ocation"] instead of top.location).
A smarter technique would be to track which URLs were redirecting using Ajax requests back to the server. (e.g. if the iframe is still there after it has loaded, send an Ajax request back to your server). You can't 100% guarantee the accuracy of those requests, since they come from the browser, but you can at least use them to build up a manual blacklist.
You also can't force the iframe to break out into another window.
You can use the sandbox attribute introduced in HTML5 to prevent the iframe buster. Just don't include allow-top-navigation in the whitelist:
<iframe sandbox="allow-forms allow-popups allow-pointer-lock allow-same-origin allow-scripts"
src="foo.html"></iframe>
Are you talking about an embedded iframe setting top.location? There's no way to prevent that as far as I know.
If you're worried about the contents of an iframe doing something you don't want, you could consider sanitizing the contents of that frame and hosting it yourself. Obviously this is very tricky, but it's pretty much the only true solution. See Caja for a project that does this. This limits what you can actually host of course (if the code you're hosting uses XHR you're outta luck, for instance).