Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does %26 get decoded to & when passed as a parameter to a JavaScript function from a link?

We've got a menu in out web app that uses <a> tags to load pages in the main frame.

A typical item in the menu would be something like:

<a target="mainframe" href="/servlet1?param1=val1&parma2=servlet2?s2p1=val2%26s2p2=val3&param3=val4">Menu Item 1</a>

We needed to add some JavaScript validation before the link is requested so I changed it to:

<a target="mainframe" href="javascript:validate('/servlet1?param1=val1&parma2=servlet2?s2p1=val2%26s2p2=val3&param3=val4')">Menu Item 1</a>  

(I know that javascript:function in a link is bad practice but we use a 3rd party library to generate the menu so I can't change this part of the code)

Servlet1 expects:
param1='val1'
param2='servlet2?s2p1=val2%26s2p2=val3'
param3='val4'

Servlet1 then forwards to the value of param2 so Servlet2 expects:
s2p1='val2'
s2p2='val3'

However when I put an alert in my validate function to check what is passed in:

function validate(href) {
    alert(href);

    ...validation code...
}

it is giving:
/servlet1?param1=val1&parma2=servlet2?s2p1=val2**&**s2p2=val3&param3=val4 (note the bold & which was %26 in the above function call)

The %26 is getting converted to an & when it is passed into the JS function which would not normally happen until the request is forwarded to Servlet2. Because the %26 has already been changed to an & the s2p2 request parameter gets picked up by servlet1 instead of servlet2.

Basically my question is why does the %26 get converted to a & at this point just by passing it as a parameter to the function from the href attribute when if you do onClick="validate('/servlet1?param1=val1&parma2=servlet2?s2p1=val2%26s2p2=val3&param3=val4')"
it stays as %26 as you'd expect?

like image 467
Chris R Avatar asked Dec 06 '22 04:12

Chris R


2 Answers

<a target="mainframe" href="javascript:validate('/servlet1?param1=val1&parma2=servlet2?s2p1=val2%26s2p2=val3&param3=val4')">Menu Item 1</a>

Urgh. You have a URL, embedded in a URL, all embedded in another URL! That's too many levels of escaping for the human mind to cope with.This:

javascript:validate('/servlet1?param1=val1&parma2=servlet2?s2p1=val2%26s2p2=val3&param3=val4')

is itself a URL. Albeit a javascript: pseudo-URL, which you should never use. It is decoded to the JavaScript command:

validate('/servlet1?param1=val1&parma2=servlet2?s2p1=val2&s2p2=val3&param3=val4')

at which point you have already lost the %26. Now when you use that as a URL itself, it will fail.

Avoid multiple-encoding problems by moving the scripting out into a JavaScript block (or external script) instead of an HTML attribute:

<a target="mainframe" class="validateme" href="/servlet1?param1=val1&amp;parma2=servlet2?s2p1=val2%26s2p2=val3&amp;param3=val4">Menu Item 1</a>

(Note here also the necessary HTML-escaping of ampersands.) Then from script do:

// find 'validateme' links and add event handler
//
for (var i= document.links; i-->0;)
    if (document.links[i].className==='validateme')
        document.links[i].onclick= validate;

Then in your validate function simply return true if all is OK and you want the link to be followed, or false to stop it.

like image 115
bobince Avatar answered Dec 09 '22 15:12

bobince


No, the %26 is (correctly) interpreted as & when the HTML file is first read into the browser, and not when passed into the JavaScript function. If you want the literal sequence of characters "percent two six", then you must encode that as %2526.

like image 38
Jonathan Feinberg Avatar answered Dec 09 '22 16:12

Jonathan Feinberg