Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detect difference between & and %26 in location.hash

Tags:

javascript

Analyzing the location.hash with this simple javascript code:

<script type="text/javascript">alert(location.hash);</script>

I have a difficult time separating out GET variables that contain a & (encoded as %26) and a & used to separate variables.

Example one:

  • code=php&age=15d

Example two:

  • code=php%20%26%20code&age=15d

As you can see, example 1 has no problems, but getting javascript to know that "code=php & code" in example two is beyond my abilities:

(Note: I'm not really using these variable names, and changing them to something else will only work so long as a search term does not match a search key, so I wouldn't consider that a valid solution.)

like image 576
Eric Caron Avatar asked Nov 15 '25 09:11

Eric Caron


2 Answers

There is no difference between %26 and & in a fragment identifier (‘hash’). ‘&’ is only a reserved character with special meaning in a query (‘search’) segment of a URI. Escaping ‘&’ to ‘%26’ need be given no more application-level visibility than escaping ‘a’ to ‘%61’.

Since there is no standard encoding scheme for hiding structured data within a fragment identifier, you could make your own. For example, use ‘+XX’ hex-encoding to encode a character in a component:

hxxp://www.example.com/page#code=php+20+2B+20php&age=15d

function encodeHashComponent(x) {
    return encodeURIComponent(x).split('%').join('+');
}
function decodeHashComponent(x) {
    return decodeURIComponent(x.split('+').join('%'));
}

function getHashParameters() {
    var parts= location.hash.substring(1).split('&');
    var pars= {};
    for (var i= parts.length; i-->0;) {
        var kv= parts[i].split('=');
        var k= kv[0];
        var v= kv.slice(1).join('=');
        pars[decodeHashComponent(k)]= decodeHashComponent(v);
    }
    return pars;
}
like image 57
bobince Avatar answered Nov 17 '25 23:11

bobince


Testing on Firefox 3.1, it looks as if the browser converts hex codes to the appropriate characters when populating the location.hash variable, so there is no way JavaScript can know how the original was a single character or a hex code.

If you're trying to encode a character like & inside of your hash variables, I would suggest replacing it with another string.

You can also parse the string in weird ways, like (JS 1.6 here):

function pairs(xs) {
  return xs.length > 1 ? [[xs[0], xs[1]]].concat(pairs(xs.slice(2))) : []
}

function union(xss) {
  return xss.length == 0 ? [] : xss[0].concat(union(xss.slice(1)));
}

function splitOnLast(s, sub) {
  return s.indexOf(sub) == -1 ? [s] : 
                                [s.substr(0, s.lastIndexOf(sub)),
                                 s.substr(s.lastIndexOf(sub) + sub.length)];
}

function objFromPairs(ps) {
  var o = {};
  for (var i = 0; i < ps.length; i++) {
    o[ps[i][0]] = ps[i][1];
  }
  return o;
}

function parseHash(hash) {
  return objFromPairs(
           pairs(
             union(
               location.hash
                       .substr(1)
                       .split("=")
                       .map(
                         function (s) splitOnLast(s, '&')))))
}

>>> location.hash
"#code=php & code&age=15d"
>>> parseHash(location.hash)
{ "code": "php & code", "age": "15d" }
like image 33
6 revsAndrey Fedorov Avatar answered Nov 17 '25 23:11

6 revsAndrey Fedorov