Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Encoding URL components with an ampersand &

Seems like a very simple question here:

I've got a program where someone is entering a string M&S in a form and running a query. I understand the & is a reserved character and therefore must be encoded. The problem is it seems to be requiring encoding twice in some contexts.

If the URL is used in a javascript onClick event, normal URL encoding seems to work fine (here the operator can click on a column header to sort):

<td onClick="AJAX_Get('http://10.0.0.195/program.exe?Qry147=M%26S&sortmethod1=161')">

However, if the URL is used in an anchor (although the anchor actually uses AJAX), it seems to need encoding twice:

<a href="javascript:AJAX_Get('http://10.0.0.195/program.exe?Qry147=M%2526S&sortmethod1=147')" title='Refresh'>Refresh</a>

Both of the examples above work fine. However they are hand-generated test cases. Unfortunately, in the application, when I'm actually generating the URL, I don't know how it's going to be used.

If I encode the URL parameter once (M%26S), it works fine in onClick. But used this way in the anchor, the server sees the URL as ...Qry147=M&S&sortmethod1=147... - so it must have been unencoded before being given back to the server.

If I encode it twice (M%2526S), the anchor works, but for the onClick, the server sees ...Qry147=M%2526S....

I get the feeling I'm missing something here. Is there a way to make this work the same in both cases?

like image 453
asc99c Avatar asked Jul 02 '10 15:07

asc99c


1 Answers

If you construct the whole HTML text using simple steps, some of the difficulties will disappear. So, by taking your example, you want to encode the following query parameter:

M&S

When you embed this string as a query parameter in a URL, you have to urlencode it, as you already know. The urlencoded string is M%26S. The complete URL then looks like this:

http://10.0.0.195/program.exe?Qry147=M%26S&sortmethod1=147

Now this URL is embedded in JavaScript code, and in this case you only need single quotes at both ends:

'http://10.0.0.195/program.exe?Qry147=M%26S&sortmethod1=147'

The whole JavaScript code looks like this:

AJAX_Get('http://10.0.0.195/program.exe?Qry147=M%2526S&sortmethod1=147')

Now this whole text is used in an HTML context that is interpreted as a URL, so you need to urlencode it again:

AJAX_Get('http://10.0.0.195/program.exe?Qry147=M%2526S&sortmethod1=147')

And finally, since you are embedding this text in HTML, you need to htmlescape it:

AJAX_Get('http://10.0.0.195/program.exe?Qry147=M%2526S&amp;sortmethod1=147')

That's why you end with:

<a href="javascript:AJAX_Get('http://10.0.0.195/program.exe?Qry147=M%2526S&amp;sortmethod1=147')" title='Refresh'>Refresh</a>

I usually avoid these encoding challenges by not putting the string M&S directly into the onclick event or the anchor. In general, you cannot encode the onclick event and the anchor in the same way, since the decoding process for both is different:

onclick: html -> js -> url
anchor: html -> url -> js -> url

But wait ... if you write a helper function like this, it works:

function myQuery(q) {
    var encodedQ = encodeURIComponent(q); // TODO: which character encoding is used here?
    var url = 'http://10.0.0.195/program.exe?Qry147=' + encodedQ + '&sortmethod1=147';
    var response = AJAX_Get(url);
    // TODO: handle errors
}

Now you can write:

<a href="javascript:myQuery('M&amp;S')">anchor</a>
<a onclick="myQuery('M&amp;S')">event</a>

This trick works because there is no % anymore in the anchor case.

like image 90
Roland Illig Avatar answered Oct 18 '22 13:10

Roland Illig