SWF caching issues accross browsers

Here are some quick notes on various browser caching behavior. I was fiddling with Wireshark to optimise my caching strategy and found some quirks one should be aware of.

First, let's define some reload vocabulary.

  • initial load is the first time the page is loaded, when the cache is empty.
  • hard reload is the classical reload. Clicking the Reload icon, or pressing Ctrl+R / F5.
  • link reload is when the page is loaded again after you click on a link to it
  • soft reload will be loading the page again by pressing enter in the address bar
  • navigational reload is the reloading of a page that occurs while using the previous/next buttons.

For the rest of this blog post, we will assume an HTML page loading the same .jpg file multiple times and the same swf file multiple times too (we will use both IE specific and general swf markup).

The html itself is not cached.

Also, all those static assets will have a Cache-Control:max-age=29030400 header.

All the network tests have been made using Wireshark.

Chrome

Initial load : Download of jpg and swf once each. Perfect.

Link reload & navigational reload: Nor jpg nor swf is loaded again. Perfect.

*Soft reload & hard reload *: The jpg is downloaded again but not the swf. Chrome sends a Cache-Control:max-age=0 header to the jpg request, to force loading it again.

Reloading images is a standard behavior on images, but I wouldn't have expected it on soft reloads.

Safari 5 Win

Safari behaves much like Chrome, with one important difference. It does not cache swf files at all.

Initial load : The jpg gets downloaded perfectly, but the swf gets downloaded multiple times, one per instance.

Link reload & navigational reload : The jpg is correctly fetched from cache, but the swf are all downloaded again. No swf is ever cached.

Soft reload & hard reload : Much as Chrome, Safari forces the reload of the jpg here. As you might guess, it also reload all the swf too, multiple times.

It means that Safari 5 does not cache any swf file at all. That's pretty impressive.

This same caching bug is talked about on this other blog. I've also tried including flash files from within another flash file (much like the Satay method). The results are the same : no swf flash is ever cached, even in the same html request.

It is supposed to have been fixed in Safari Mac (anyone can confirm this? I don't own a Mac) but the issue is still here on Safari Windows.

IE6, IE7 and IE8

IE6, IE7 and IE8 behaves the same here. They have a less severe version of the bug than Safari 5. At the time of writing I didn't have IE9 to test on it.

Initial load : Same bug as Safari here. The swf are downloaded multiple times, once for each instance. The jpg is only download once.

Link reload, navigational reload and soft reload : This time, everything is fetched from the cache. Actually, even the html is seems fetched from cache (I didn't investigate that much)

Hard reload : Html and jpg are fetched from the server, swf file stays in the cache.

It appears that (surprisingly) IE behaves quite well. Its caching behavior is more aggressive than the others (soft reload is really soft). However, it still have a nasty side effect of loading swf files multiple times on the same page. Shouldn't happen a lot in the real world, but still nice to know.

Firefox 4.0

Initial load : No issue arising. It does fetch each resource once.

Link reload, navigational reload and soft reload : Fetches everything from cache, nice.

Hard reload : Re-request jpg and swf files by adding a Cache-Control: max-age=0 request header. This feels like the expected behavior.

Take care of that favicon

Even if you are not referencing it in your HTML markup, browsers will try to get a file named /favicon.ico on your server root. Let's see some good practice regarding this file.

Make it small

The smaller the file, the faster it will get downloaded. As it is a less than important file, we don't want to delay the loading of our page for such a tiny graphic. The default file format for such a file is image/x-icon, meaning the .ico extension.

I think it's a Microsoft legacy format, but well understood by every browser. Be careful when putting your favicon, don't just find a cool .ico file and drop it here. Icon files are containers, they hold various image format ranging from 16x16 to 512x512.

You clearly don't need the bigger one and the 16x16 will be highly enough. So, be careful.

The best way of creating the favicon I've found is to first create it as a .gif, then running ImageMagick upon it. On Linux, this means running

convert favicon.gif -resize 16x16! favicon.ico

Make it cacheable

This file will be requested by the browser on every request, so you'd better make it cacheable to limit the number of requests.

Also, note that you can't change the name of the file, favicon.ico will always be fetched.

I choose to cache mine for a year, like any other static asset. I could have gone for a month, to allow updating them more often but I've never ever changed a favicon, so a year seems better.

A note on Safari Win

From the tests I've done, almost all browsers behave the same regarding favicon fetching and caching : the fetch it last, and do not issue a Cache- Control:max-age=0 on a refresh to force redownloading it.

Except Safari Win. It fetch it along other downloads and re-dewnload it on a page refresh.

PHP sessions and the Pragma:no-cache header

You may have seen the Pragma:no-cache response header on various website (if you're that kind of guy actually reading HTTP response headers...).

What you may not know is that this Header doesn't actually exists. The Pragma header is supposed to be *Request *header, not a *Response *header.

It is not only useless, it may also trigger strange caching bugs in IE6. I'm sure you know what kind of IE6 quirks I'm talking about. The best is to remove it, just to be sure.

This is a common misconception (I myself didn't know that before reading this excellent caching tutorial), and that header is still returned in a lot of request.

For example, if you set your session.cache_limiter to nocachein your php.ini, then PHP will send this header (as defined in the sessioncachelimiter doc. This is obviously wrong.

It also adds a weird Expires: Thu, 19 Nov 1981 08:52:00 GMT header. I don't like it as it allow easy fingerprinting of the server-side technology used.

I changed my session.cache_delimiter value to private_no_expire to return better headers.

First, it removed the useless Pragma, but it also removes the Expiresheader (Cache-Control is enough).

Working on Wednesday #1

Starting June 15th, I'll stop working at my day job for one day a week. Instead, I'll use this time to work on personal projects.

After more than 3 years of freelancing, I've been working full time for a very nice young company (making a great social game) for the past 6 months. Today, with the public release of the game, I find myself missing freelance.

I liked being able to sleep when too tired, working late at night when really productive, reading a log of blog posts on various subjects, learning new cool stuff other did. I kinda miss that on my new job.

Sure our project is damn cool and I really like working on it. I learn a lot, in fields that I was interested in but never had the chance to explore (server administration, CDN configuration, memcache, large number of users, etc).

But on the other hand, I'm almost only doing server-side work. I relatively interesting part of Javascript (nothing fancy) and a really small part of CSS.

And I miss all that front-end part of the job. I also get kind of tired of using cakePHP. I do like it a lot, but the more I write PHP and read posts about Ruby, the more I want to switch.

Working 4 days a week

I finally made a deal with my boss, for not working on Wednesday. I want to use that time to relax and learn all those things.

The last time I was working full time for a company, I finally quit because I thought I was waaaaaaay late behind all the current tech trends. It took me a couple of month to learn the cool stuff I'm armed with today : jQuery and cakePHP.

This time, I want to re-learn a whole new world, a better one. Using all I learnt those past years to make a fresh start.

What I want to learn

There's a lot of things I would love to learn, unordered :

  • vim : I want to be able to write code on any machine, easily, and fast
  • ruby / rails : I want to learn Ruby to be able to fully understand Rails. I have a pretty strong knowledge of cakePHP so I guess Rails won't be too hard for me.
  • git : I like Mercurial, but git seems to be the de-facto VCS for all the social geeks and rails coder, so why not ?
  • sass and haml : Those seems awesome, and were part of the things that make me want to try ruby. Writing CSS and HTML in a non-painful way. I already want to write modules (or are they called gems?) to enhance them, adding webperf optimisations on the fly (creating sprites/dataURI, optimizing selectors, etc).
  • CoffeeScript, Kafeeine or equivalent : Following the logic behind sass, I want to be able to write Javascript easily. I always encounter issues when my jQuery code became too big, everything gets tangled together. Backbone.js seems interesting too. I'll have to test all those solution.
  • nodejs : Because it looks kinda fun. I haven't really understand how it works yet, but it looks fun anyway :)
  • TDD : This is not a technology, but a way of writing code that I want to learn. I tried it in cakePHP, but I spent so much time writing tests (and making them work), to finally change the implementation and broke the tests that I finally gave up. I still have to understand HOW to do it properly. I thought I read somewhere that this principle was directly intergrated into Ruby (or was it Rails ?) development.

To summarize, I want to learn the good tools that will let me focus on the project(s) I want to make, not fighting to use tools to bend them to my needs. Writing "uncompiled" css, html or Javascript and having some automation tool to automatically transform it in the most usable version to use only.

Also, I have already written a pretty decent cakePHP CMS, with a full featured admin panel that I used when making website for clients. I wanted to put it open source for all to enjoy but never really knew how to do it. I don't yet know if I want to create a whole new CMS in Rails, or if I'll do custom dev for each project, or use (and enhancing) existing CMS.

That's all for now

I might have forgotten stuff (I'd want to try couchDB/mongoDB, getting better at using Linux everyday), but here is a dump of all the things I want to achieve in the next 6 month, one day per week. I'll try to post a summary of what I learned each Wednesday, hoping that it would help others (I know I'll surely enjoy looking back at it later).

Missing bits of the official Facebook documentation

As a complement to my post about FB.ui undocumented hard limit, here are some other parts that should be in the documentation.

Custom html tag

You have to add xmlns:fb="http://www.facebook.com/2008/fbml" xmlns:og="http://opengraphprotocol.org/schema/" to your main <html> element.

If you don't, the <fb:like> (and possibly other <fb:*> elements) won't work in IE. I guess those unorthodox tags won't be interpreted by IE until you define the correct xmlns.

Adding a #fb-root

You also have to add a <div id="fb-root"></div> in your html code. I guess the Javascript API use it for some stuff, but I don't really know why.

The Javascript SDK logs an error message asking for this missing element if you don't have it.