The Problem with document.location.hash

Written by Ryan on May 10th, 2010

SourceAudio, like a lot of ajax heavy applications, uses the hash to store state information. For example, when you search, you might end up on a url like

The “page” is the “explorer” and the parameters are after the question mark. There are a number of ways you can format your hash but using the standard url format has been a pretty good solution for us. At least until today.

In the code, when we need to get that hash information, we would use document.location.hash but I realized today that Firefox has a problem when you start having ampersands in values. Naturally, you’d encode them with escape() to end up with something like #explorer?s=bump%20%26%20grind&pg=1 (from “bump & grind”) but when you try to retrieve that with document.location.hash, Firefox automatically un-escapes the hex codes.

Try it out. Go to firebug and run

document.location.hash = 'a%20%26%20b';

You’d hope to see ‘a%20%26%20b’ but instead, you get ‘a & b’.
Just ran Chrome out of curiosity. It returns ‘a%20%26%20b’, as does IE8.

I guess there are applications where Firefox’s behavior would be useful but it’s a real problem when the ampersand is a special character in your syntax. There’s no way to tell the difference between an & and a %26. So if you’re trying to parse ‘s=bump%20%26%20grind&pg=1’ so ‘s’ is ‘bump & grind’ and ‘pg’ is ‘1’, you instead get ‘s=bump & grind&pg=1’ which parses to ‘s’ = ‘bump ‘, ‘ grind’ = ”, and ‘pg’ = ‘1’. It’s no good.

So, what’s the answer? Apparently it’s not to use document.location.hash at all. Consistently across browsers, document.location.href contains the full path, without any un-escaping. So if you want the hash, all you have to do is

var hash = document.location.href.replace(/^[^#]+#/, '');

Just don’t trust document.location.hash
Or the Firefox developers, it seems.


1 Comments so far ↓

  1. Rory O'Kane says:

    Even document.location.href is not completely safe from being messed with – spaces are always escaped in Firefox 22. I found this out by running this in Firebug:

    >>> document.location.hash = 'a%20%26%20b';
    >>> document.location.href.replace(/^[^#]+#/, '');
    >>> document.location.hash = 'c & d';
    "c & d"
    >>> document.location.href.replace(/^[^#]+#/, '');

    Even though I used spaces when assigning to hash, they came out as %20.

Leave a Comment