In going through cases we have with some customers, we’ve seen a few instances where Internet Explorer does not cache shared static resources. Within Load Tester, this problem becomes immediately apparent:
Note that the shared CSS, Javascript, and images are re-requested again on the About page and every other recorded page that uses them. Note also, these files don’t come back with a 304 (Not Modified), but instead the full content of the file is sent over and over again through a HTTP 200. Normally, the browser should load these files once, and not need to request them again within the same user’s session.
This problem can be serious for both end users and server administrators. For end users, the browser must load more, and users must wait longer for each page to render. For servers, it means Internet Explorer users are consuming much more bandwidth than would normally be expected.
This case makes for a good example of how we can use Load Tester to help us track down the problem. If you are interested in using Load Tester to examine headers, please read on. If not, you may skip directly to The Solution.
So what is going on here? Let’s take a look at the re-request of the masks.js javascript file:
Here, we see that IE does not send an “If-Modified-Since” or “If-None-Match” header, as it normally would do if it was checking a cached file to see if it were stale. Thus, even though IE is re-requesting the file, it is requesting it the same way as if it had never requested the file before. The response headers seem pretty mundane though: there are no “Cache-Control” or “no-cache” directives, and a “Last-Modified” date is supplied, though an ETag is not.
We can see from the headers that the requests are delivered from an IIS 7.5 server, though the headers do not themselves reveal whether or not IIS is serving the files directly, or proxying the requests to an application server. Our first step to replicate the environment is to set up our own IIS 7.5 server, and allow it to serve the files directly. When we re-record in this environment, we see that IE suddenly has gone back to it’s expected behavior: static files are loaded once the first time they are referenced, and not reloaded on subsequent pages. Next, we try putting the same static files into Apache. Though mod_asis, we can have Apache send the same headers to Internet Explorer as our user’s production server, with the exception of the Date & Server headers. As with IIS, we still see the Internet Explorer will request static files only once per session. Looking at the headers sent back from Apache for the masks.js file:
Here, Apache has modified the Date & Server headers, just as the Apache docs said it would. The other headers appear the same – except for the Last-Modified header, where Apache has modified the time zone. Since we’ve tested IIS earlier, it seems unlikely that the difference in the server header is causing this behavior. Testing the customer’s system again, we still get current date headers back, and we can rule out the Date header too. That brings us to the Last-Modified header.
To test this header, a simple servlet was constructed to write some static content, and include an ETag and a Last-Modified header using the server’s local timezone:
This test was made by recording the “uncachable-page.html”, then clicking back and going to the URL again. The file “uncachable.html” is the only file where the Last-Modified is written using the local timezone. Here, we see that IE is, in fact, not caching the file we suspect is “uncachable”.
Now, all we have to do to fix this is change the server’s local timezone to GMT, which will cause the Last-Modified header to be sent in GMT. Re-recording using the same “back and click again” method, we now see that IE is now able to cache our previously uncachable file:
For completeness, we also tried this same test against other browsers. Using current versions of FireFox and Chrome, it appears that both browsers will accept local time zones and cache the responses. So far, we have not found any other browser that does not cache files served with a local time zone other than IE. Further testing shows that this behavior is consistent for current versions (at the time of this writing) for both IE 8 and IE 9.
As you may have noticed from the initial screen shots, we initially observed this behavior coming back with IIS 7.5 headers. However, after testing IIS 7.5 directly, it appears that IIS is not the problem. In the initial case, this customer was using IIS as a front-end for Adobe ColdFusion. After trying a similar configuration using a current version of ColdFusion both directly and behind IIS, we were not able to replicate the behavior. Thus, it would seem that upgrading the application server resolves the problem in this case.
It is interesting that the Apache httpd server (version 2.2) rewrites the Last-Modified header with a GMT timezone, which proactively corrects this problem. Thus, it would seem users using the Apache webserver as their front-end may also escape having this problem.
When a server is sending a cachable static resource, and the browser is not caching it, it seems clear that there is a bug somewhere. However, in this case, Internet Explorer is not the party violating the specification. RFC 2616 (the HTTP 1.1 specification) §3.3.1 clearly states: “All HTTP date/time stamps MUST be represented in Greenwich Mean Time (GMT), without exception.” Thus, any server sending timestamps in the HTTP headers, which are not sent in GMT would be considered defective.
Localization standards also seem to discourage use of three character timezones (except for GMT), citing examples where codes are not internationally standardized, and in some cases lead to ambiguity.
Even though these reasons suggest changes should first be made on the server, in this author’s opinion, Internet Explorer can do better for end users who don’t have control of the server. RFC §3.3.1 additionally states:
Note: Recipients of date values are encouraged to be robust in accepting date values that may have been sent by non-HTTP applications, as is sometimes the case when retrieving or posting messages via proxies/gateways to SMTP or NNTP.
We’ve shown how a misbehaving server sending Last-Modified headers for static files using a timezone other that GMT results in Internet Explorer treating static files as uncachable. This in turn leads to Internet Explorer users consuming substantially more bandwidth from the server than would be reasonably expected otherwise. Here are some suggestions to correct the problem:
I hope that this helps other users understand this problem if they’ve seen it in their own sites. We’ve also shown that Load Tester can be a powerful tool for tracking down performance problems, even without scratching the surface of Load Tester’s capabilities. Of course, if you have any questions, our friendly support staff will be available to answer them!
Happy Testing!
-Frank
Engineer at Web Performance
Frank is an engineer for Web Performance. He is also an advocate for correct fire safety procedures whenever applying massive load to production test rigs.