posted on February 27, 2012 in browser, CORS, deployment

Firefox Is The New Enemy

When I first started designing websites there was one enemy. Internet Explorer. No matter what you did it did not work. Sites were designed for "Firefox 0.7 ++" or just did look horrible. Well they did work but only as plain/text document. Internet Explorer lost a serious amount of market share, the new versions became more and more standard compliant and you had less work creating stunning sites that work on all browsers.

Most people learned to use Firefox or another alternative the last few years. Even if it is not as necessary as it was. But today I ran into something only Firefox screws up. Cross-Origin Resource Sharing.

Explaining The Setup

Sounds complicated, doesn't it? Well let me give you an easy example why I ran into this problem. I deployed some Django sites today and they share the same static files. Let us assume we have three domains.

They all represent one Django project and are all hosted on the same server. Since I do not care about the flavor of the month I used lighttpd as webserver. Do not start giving me all the reasons to use nginx. I know them and I still decided to stay with lighttpd. All Django projects run as wgsi on a different port using gunicorn.

So what you basically do is set the document root of your webserver to the static directory that contains all the files and create three conditions, for every domain, to tell lighttpd to proxy requests to the corresponding project. I will talk about this setup in another post.

Accessing Your Static Files

Now you tell your Django projects that they should access the static files through http://$ip/. Everything looked fine till I did the last check on my Windows box with Firefox and Internet Explorer.

I have some fonts embedded in my stylesheets. font-face works fine if you remember to convert your fonts in a format Internet Explorer understands. But Firefox showed the fallback font. What happend?

Firefox refuses to load files that are not on the same domain as your website. Loading something form $ip when you opened domain3.tld does not work. I am currently not sure what they try to achieve with this behaviour but I am sure that there are some good reasons.

Good Reasons For Everything

When I talk about good reasons and Firefox in one sentence you should read it in the most sarcastic voice you can imagine. There is a reason why I call Firefox useless these days. Of course it did something great in the past. Thanks to Firefox we had a tiny, fast browser that was a perfectly fine alternative to Internet Explorer and Mozilla.

After the 1.0 release everything went downhill. Firefox became bigger and slower. At some point they decided that releasing one major release every week is the best idea since sliced bread and that those stupid users are the best beta testers you can get.

It could be possible that I am a bit exaggerating but you get the idea and I think you can understand why I declare Firefox the new Internet Explorer.

Solving This Problem

There is an easy way to solve it. You just have to tell Firefox that it is okay to access those files. Add Access-Control-Allow-Origin to your response header and everything is fine.

The worst solution I know is patching this with your application. There are better options. Use your webserver.

Lighttpd

Load mod_setenv and add the following line to your configuration.

setenv.add-response-header = ( "Access-Control-Allow-Origin" => "*" )

This allows every domain to load stuff from your server. You could replace the wildcard with domain names to restrict access.

If you are on another server just search in your documentation how to add a response header and you are fine. Quick examples, without modules or anything else.

Apache

Header set Access-Control-Allow-Origin "*"

IIS

add name="Access-Control-Allow-Origin" value="*"

NginX

add_header Access-Control-Allow-Origin *

Restricting Access

I strongly suggest you do not use the wildcard. Every domain can load your files. If you are planning to run a CDN this could be viable, for everything else think about what you are doing.

If you are not using subdomains in your Django installation you can also create a subdomain. But this would not work for my current setup since all subdomains have to be processed by Django.

I do not know another browser beside Firefox that implements CORS. But it could become a standard. There could be some reasons why they implemented this "feature". Being prepared when something from another domain does not load one day, after a browser update, is a good idea.

I would love to talk to you about this post, your ideas or awesome projects.

I am @fallenhitokiri on Twitter and GitHub or you can send me a mail.