Force mobile browser to skip cache when browser is reactivated - mobile-safari

I've got a single-page app that I'm updating several times a day. In spite of aggressive cache controls on the page, mobile users (especially Safari users) are frequently several days out of date.
I know for a fact that the page is being reloaded, ie, that my startup JS is being executed correctly. So browsers like mobile Safari are simply loading the page from cache despite my headers and meta tags, probably when the browser itself is reactivated after being closed.
How can I prevent this behavior? I'd rather not resort to forcibly calling location.reload(), as that gets complicated (need some timestamp in local storage), could disrupt the user, and could result in slower perceived loading times.
I'm already using aggressive cache prevention measures:
<Files index.html>
Header set Cache-Control "no-cache, max-age=0, must-revalidate"
Header set Pragma "no-cache"
</files>
<!-- srsly plz dont cache this page kthxbye -->
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Expires" content="0">

Why Safari isn't reloading over the network I don't know, but you might try adding location.reload() to a listener on the window's focus event. If the cache is still valid, it should reload basically instantly, and if it's not it'll pull the fresh data.
window.addEventListener("focus", () => {
// other logic here, perhaps to restrict how often it reloads
location.reload();
})

Related

How to Remotely force a client to purge a cached website?

We are experiencing an issue where a previous version of our home page is being displayed. Even though there has been changes since then, the web page will always show the old version.
This issue stems from us using a WordPress plugin that added a
Last-Modified: Tue, 19 Apr 2016 15:18:40 GMT
header to the response.
The only way found to fix this issue is by force refresh on the browser. Is there a way to invalidate that cache remotely for all clients ?
The Request-Response header
If you mean the stylesheets or javascript for example you can update the version of the stylesheet see below for an example
<link rel="stylesheet" type="text/css" href="mystyle.css">
You can change to
<link rel="stylesheet" type="text/css" href="mystyle.css?v=1.0">
Notice the ?v=1.0 parameter at the end of the source, this works for Javascript also.
If you need images and things to update you can find lots here about cache busting here
Refresh image with a new one at the same url
you can also try adding
<META HTTP-EQUIV="CACHE-CONTROL" CONTENT="NO-CACHE">
<META HTTP-EQUIV="EXPIRES" CONTENT="Mon, 20 Feb 2012 00:00:01 GMT">
To the Head of the HTML Page.
Browsers are going to honor the cache settings that were originally provided to it, you should be able to look in the developer tools of the browser to see what the cached headers are.
For example, if the content sent something like:
Cache-Control: public, max-age=86400
Then it will have no reason to request an updated version of the content from your server for a day.
If the server is able to handle the load of receiving requests for the content, you can do ensure that there is an ETag and Last-Modified header, and then use a short expiration time, such as:
Cache-Control: public, max-age=600
ETag: abcdefg
Last-Modified: Tue, 19 Apr 2016 15:18:40 GMT
Then, after 10 minutes the browser will issue a request that asks the server if the content has changed. If not, the server should issue an empty 304 Not Modified response to indicate no difference. So this saves on your bandwidth and the only cost is however "expensive" resource-wise it is to determine the headers to send.
I would absolutely suggest using small cache times for your primary HTML (or any dynamic content) if you know it will change as the entire purpose of those caching headers is to allow browsers to serve as quickly as possible the version they have as well as save you on CPU and bandwidth.
Side note: If you were able to "reach out" to it in that way, it would actually be somewhat terrifying.
Based on all of the information provided, you're missing on Varnish HTTP Purge plugin and/or have not configured the VCL for it.
If you're seeing old cache version for the homepage this means that the page's cache was not purged after updating its contents in Wordpress admin.
In a typical scenario for Wordpress, you will set maximum cache lifetime and use a plugin like the one mentioned to invalidate cache based on relevant Wordpress hooks.

why my session didn't get expired?

I created an empty mvc3 project.
It has one controller ("home") and 2 actions ("index", "about")
I am using sqlserver to save my session.
here's my config file.
<sessionState mode="SQLServer" cookieless="false" timeout="1" sqlConnectionString="Data Source=localhost;Integrated Security=True;MultipleActiveResultSets=False">
time out is 1 min.
in index page. i created a session
Session["currentTime"] = DateTime.Now.ToString();
in my about page, I write it out in the view.
#Session["currentTime"]
First time, I opened up the about page, current time shows up. I leave the page alone for 5 mins, then go back refresh it. the old currentTime still there. I set timeout to be 1, so it should expired now and should show nothing on the page.
maybe I totally misunderstood how session works. please tell me why session value still there after its expired.
Edit:
its not the cache. I added following code to disable cache. still have problem.
<meta http-equiv="cache-control" content="max-age=0" />
<meta http-equiv="cache-control" content="no-cache" />
<meta http-equiv="expires" content="0" />
<meta http-equiv="expires" content="Tue, 01 Jan 1980 1:00:00 GMT" />
<meta http-equiv="pragma" content="no-cache" />
I think I found hte problem, not sure how to fix it.
I cleared my cache from Chrome. opened up "/home/index" page to create session, then go to "/home/about" page. check the DB. there's one session created. double checked "created" and "expires" field. confirmed that it will expired after one min.
then I walked away from my computer for 5 mins. after I come back and refresh the "/home/about" page. Session still there, not expired. query my Session table, notice that "expires" field changed to 1 min + the time I refresh the page. why expires field changed?????????
2nd Update:
I believe this is what the problem is. The SQL session provider doesn't actively monitor the Expires column in the session table. Instead, sessions aren't "officially" expired until they are removed from the table, which is done with a SQL Agent job that calls the DeleteExpiredSessions stored procedure. By default, the job is configured to run every 60 seconds.
i pretty sure my sql agent is not running. but dont know how to turn it on. please let me know if you have any ideas.
There are many things which could be possible over here. The time out as set in config is "1" min, so your session variable is bound to time out.
The situation that you are facing(and I am 90% sure), is the case of caching. Your Index page default controller action must be HTTP get. Put a button inside your page and then try to refresh your web page using button. The button will make a post to server. I am sure then the session variable would not persist.
UPDATE 2
Please see following the link to see how to turn on the Sql Agent. Please turn it on and let us know if it worked or not
Smells like caching issue. Which browser you are in?
The session you are using in browser is a 'guest' session which is initialized for all controllers (except sessionless, of cause). Even if it get expired, new one will be created and timespamp should be placed inside. So, each time you refresh the page, you should see current time.
EDIT: (after the post updated).
If think it works exactly right. According to this you need to set regenerateExpiredSessionId field of sessionState, to re-generate expired session id. Otherwise, the existing session object is simply re-newed and re-used.
EDIT 2:
The previous edit would be valid, if cookieless is true. In your code, you mentioned cookieless is false, but for some reason it still acts as cookieless = true. Are you sure you have right parameters in sessionState.

Which browsers' back button does not generate request to the server?

I need to test my web application against a browser for which back button doesn't generate request to server.
Could you give me examples of such browsers?
That doesn't depend on the browser used, but on the HTTP response headers sent to it. If the browser is by the response headers instructed to cache the page, then it will cache the page. But if it is instructed to not cache the page, then it will not cache the page and fire a real request.
You have control over the response headers on the server side.
Internet explorer 6, not sure about 7/8. Make sure you dont have the following meta statements in your header (they will force page reload):
<META HTTP-EQUIV="Pragma" CONTENT="no-cache">
<META HTTP-EQUIV="Expires" CONTENT="-1">
Check this page for more info:
http://support.microsoft.com/kb/234067

ASP.net: Cache problem when logout

I can't find any post regarding the cache on logout so I'm going to ask this question. If there is a similar question. Please let me know.
I have a Logout page that basically call FormAuthentications signout method then redirect the user to the login page. It work fine but the problem is user can click on the browser's back button and get the cached page. I tried to set the no-cache header on my master page but that doesn't work.
Can someone point me to a article or tutorial or post some tips on how you handle this situation?
thank
Depending on your requirements a possible solution might be to set the Cache-Control header to "no-cache" on every authenticated page. This will prevent pages from being cached downstream. It could be achieved by writing a custom HttpModule that will set the header:
// Prevent the browser from caching the ASPX page
Response.Cache.SetNoStore();
You can also set this in your page's HEAD section by adding the following line of code:
<meta http-equiv="Cache-Control" content="no-cache" />
By doing that if a user clicks the Back button once he's been signed out, he will be redirected to the login form instead of seeing a cached version of his last page which could be a problem if he is using a public computer.
If you're using forms authentication, make sure the forms authentication cookie is deleted when the user logs out. As soon as the user goes to do anything on the cached page (the page they pressed the back button to get to), the site will ask the user to re-login, and then redirect them back to the original page, with fresh data. Viola!
Additionally, regarding caching of pages, you need to set a pretty good number of headers to turn the caching mechanism in the browser and proxy servers off:
"Expires" - set to some date in the past
"Last-Modified" - set to the current date/time
"Cache-Control" - set to "no-cache, must-revalidate"
"Pragma" - set to "no-cache"
That should just about make the page uncacheable. The date/times need to be in RFC1123 format (format specifier "R" in .net e.g. "Mon, 17 Apr 2006 21:22:48 GMT"). You would implement this as:
Response.AddHeader("Expires", new DateTime(1940, 1, 1).ToString("R"));
Response.AddHeader("Last-Modified", DateTime.Now.ToString("R"));
Response.AddHeader("Cache-Control", "no-cache, must-revalidate");
Response.AddHeader("Pragma", "no-cache");
Or something similar, depending on where you want to add all of the headers. I have had good success with this across many browsers and proxy servers, but nothing is fool-proof where page caching is concerned.
There's no foolproof way to accomplish this. The user ultimately has control over the cache settings and no-cache headers can't override these.
Is there a particular concern you are trying to address here (security?), or are you just trying to ensure that users aren't seeing stale data?
This is a hard problem to tackle. You can create a base page and in the constructor you can check that if the person is logged in or not. If the person is not logged in that simply redirect to the login page. This base page will be inherited by all the other ASP.NET pages.
IE6 seems to ignore some cache headers.
Another technique ontop of cache headers would be some clientside javascript to check for the authentication cookie and use history.Forward() if its not there.
Add this to global.asax and it will set the no-cache headers for all pages in the web application. Be sure that disabling caching is really what you want to do however - because caching is a performance benefit.
You can of course, also apply the same Response.Cache commands to pages individually.
This works in FireFox 3, IE7, and somewhat in Opera 9.6. (In Opera, it will work if you don't to any post requests. If you do, the page will still be accessible from the back button the first time, but not afterwards.)
protected void Application_PreSendRequestHeaders(object sender, EventArgs e)
{
if (!Request.Path.Contains("/Content/")) //We WANT images, css, javascripts to be cached!
{
//Otherwise, all of our pages contain sensitive information, and we don't want them cached.
Response.Cache.SetCacheability(HttpCacheability.NoCache);
Response.Cache.SetRevalidation(HttpCacheRevalidation.AllCaches); //for Opera. May only work on https sites
Response.Cache.SetNoStore();
}
}
There is no way you can actually stop is behavior people have removed the back button disabled it but the user would still have controls from short cut for any browser , my suggestion would be that for all those pages where you want the users to be logged in Put them on a POST method i.e. instead of a regular GET use post. What this would do is anytime a user presses the back button for that url the browser would ask the user with an alert box to post the last data cached for this request and there would be a server call where form authentication would work.
It is a bit crude using post where get might work but it solves this issue of yours.

Is there a way to keep a page from rendering once a person has logged out but hit the "back" button?

I have some website which requires a logon and shows sensitive information.
The person goes to the page, is prompted to log in, then gets to see the information.
The person logs out of the site, and is redirected back to the login page.
The person then can hit "back" and go right back to the page where the sensitive information is contained. Since the browser just thinks of it as rendered HTML, it shows it to them no problem.
Is there a way to prevent that information from being displayed when the person hits the "back" button from the logged out screen? I'm not trying to disable the back button itself, I'm just trying to keep the sensitive information from being displayed again because the person is not logged into the site anymore.
For the sake of argument, the above site/scenario is in ASP.NET with Forms Authentication (so when the user goes to the first page, which is the page they want, they're redirected to the logon page - in case that makes a difference).
The short answer is that it cannot be done securely.
There are, however, a lot of tricks that can be implemented to make it difficult for users to hit back and get sensitive data displayed.
Response.Cache.SetCacheability(HttpCacheability.NoCache);
Response.Cache.SetExpires(Now.AddSeconds(-1));
Response.Cache.SetNoStore();
Response.AppendHeader("Pragma", "no-cache");
This will disable caching on client side, however this is not supported by all browsers.
If you have the option of using AJAX then sensitive data can be retrieved using a updatepanel that is updated from client code and therefore it will not be displayed when hitting back unless client is still logged in.
Cache and history are independent and one shouldn't affect each other.
The only exception made for banks is that combination of HTTPS and Cache-Control: must-revalidate forces refresh when navigating in history.
In plain HTTP there's no way to do this except by exploiting browser bugs.
You could hack around it using Javascript that checks document.cookie and redirects when a "killer" cookie is set, but I imagine this could go seriously wrong when browser doesn't set/clear cookies exactly as expected.
From aspdev.org:
Add the following line on top of the Page_Load event handler and your ASP.NET page will not be cached in the users browsers:
Response.Cache.SetCacheability(HttpCacheability.NoCache)
Settings this property ensures that if the user hits the back-button the content will be gone, and if he presses "refresh" he will be redirected to the login-page.
DannySmurf, <meta> elements are extremely unreliable when it comes to controlling caching, and Pragma in particular even more so. Reference.
dannyp and others, no-cache does not stop caches from storing sensitive resources. It merely means that a cache cannot serve a resource it has stored without revalidating it first. If you wish to prevent sensitive resources from being cached, you need to use the no-store directive.
You could have a javascript function does a quick server check (ajax) and if the user is not logged in, erases the current page and replaces it with a message. This would obviously be vulnerable to a user whos javascript is off, but that is pretty rare. On the upside, this is both browser and server technology (asp/php etc) agnostic.
You are looking for a no-cache directive:
<META HTTP-EQUIV="PRAGMA" CONTENT="NO-CACHE">
If you've got a master page design going, this may be a little bit of a juggle, but I believe you can put this directive on a single page, without affecting the rest of your site (assuming that's what you want).
If you've got this directive set, the browser will dutifully head back to the server looking for a brand new copy of the page, which will cause your server to see that the user is not authenticated and bump him to the login page.
Have the logout operation be a POST. Then the browser will prompt for "Are you sure you want to re-post the form?" rather than show the page.
I don't know how to do it in ASP.NET but in PHP I would do something like:
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
header("Cache-Control: no-cache");
header("Pragma: no-cache");
Which forces the browser to recheck that the item, so your authentication checking should be triggered, denying the user access.
It's a bit of a strain, but if you had a java applet or a flash application that was embedded and authentication was done through that you could make it so that they had to authenticate in, erm, 'real-time' with the server everytime they wanted to view the information.
Using this you could also encrypt any information.
There's always the possibility that someone can just save the page with the sensitive information on, having no cache isn't going to get around this situation (but then a screenshot can always be taken of a flash or java application).
For completeness:
Response.Cache.SetCacheability(HttpCacheability.NoCache);
Response.Cache.SetNoStore();
Response.Cache.SetExpires(DateTime.Now.AddMinutes(-1));
The correct answer involves use of setting the HTTP Cache-Control header on the response. If you want to ensure that they never cache the output, you can do Cache-Control: no-cache. This is often used in coordination with no-store as well.
Other options, if you want limited caching, include setting an expires time and must-revalidate, but these could potentially all cause a cached page to be displayed again.
See http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.4
Well, in a major brazilian bank corporation (Banco do Brasil) which is known by having one of the world´s most secure and efficient home banking software, they simply put history.go(1) in every page.So, if you hit the back button, you will be returned. Simple.
Please look into the HTTP response headers. Most of the ASP code that people are posting looks to be setting those. Be sure.
The chipmunk book from O'Reilly is the bible of HTTP, and Chris Shiflett's HTTP book is good as well.
You can have the web page with the sensitive be returned as an HTTP POST, then in most cases browsers will give you the message asking if you want want to resubmit the data. (Unfortunately I cannot find a canonical source for this behavior.)
I just had the banking example in mind.
The page of my bank has this in it:
<meta http-equiv="expires" content="0" />
This should be about this I suppose.

Resources