41

I am using Javascript method decodeURIComponent to decode an encoded URL. Now I am having an issue, that sometimes the URL is get encoded twice during redirection between servers, sometimes it is encoded only once.

I want to check that if the URL is still encoded after calling the method decodeURIComponent. How can I do that? Any pointer would be very helpful to me.

Update - 1

If I recursively call a method and check that if the given URL still contains "%", if it contains "%" then decode it and call the method again; and if not return it to the caller, will that work?

Update - 2

For my case I have:

callBackUrl=http%253A%252F%252Fadbc.com%252FPOSM%252Fapp%252Fpages%252Fadf.task-flow%253Fadf.tfDoc%253D%25252FWEB-INF%25252Ftask-flows%25252Fcatalog-edit-task-flow.xml%2526adf.tfId%253Dcatalog%2526_adf.ctrl-state%253Db9akorh22_9%2526articleReference%253D10C00135%2526previousView%253Dcatalog-home%2526fromUCM%253Dtrue%2526articleType%253Dposm%2526developer%253Dcentral

Now I am taking the value of the callBackUrl in my js method, then decoding it and firing window.open() with that decoded URL. the parameters are same and it has:

  • adf.tfDoc
  • adf.tfId
  • articleReference
  • previousView
  • fromUCM
  • articleType
  • developer

Parameters into it. So I know there is no query string like value="%..".

Update - 3

I have written the following method:

var decodeURLRecursively = function(url) {
    if(url.indexOf('%') != -1) {
        return decodeURLRecursively(decodeURIComponent(url));
    }

    return url;
}
Tapas Bose
  • 28,796
  • 74
  • 215
  • 331
  • Seems like an issue to be fixed on the server rather than patching it on the front end. – elclanrs Jul 10 '13 at 07:33
  • I don't think it is possible, you can encode a string twice. And this may look either as twice encoded string or as an attempt to send an encoded string. – mishik Jul 10 '13 at 07:34
  • @elclanrs, maybe it is an issue in the server, but is there any way to check my requirement? – Tapas Bose Jul 10 '13 at 07:36
  • @mishik I have updated my question, could you please take a look? – Tapas Bose Jul 10 '13 at 07:48
  • @TapasBose what if you want to pass `value=%` to the server? – mishik Jul 10 '13 at 07:49
  • @mishik could you please take a look at my second update? – Tapas Bose Jul 10 '13 at 07:56
  • Could a workaround solution be to add an additional query param called encoded and set to true if it's encoded and false if it's not. Then if the url is encoded, don't encode again. Otherwise, you could add a number, encoded being the key, the value being the number of times it's been encoded, then you can decode the required number of times. – Michael Martinez Nov 28 '19 at 08:55
  • @MichaelMartinez, don't think so. Otherwise, it won't be a generic solution. Since this sanitization is done on the callee side, who is unaware of the type of caller. – Tapas Bose Nov 29 '19 at 05:31

6 Answers6

54

There is a simple way to konw if a URL string is encoded.

Take the initial string and compare it with the result of decoding it. If the result is the same, the string is not encoded; if the result is different then it is encoded.

I had this issue with my urls and I used this functions:

function isEncoded(uri) {
  uri = uri || '';

  return uri !== decodeURIComponent(uri);
}

So now I can use isEncoded as the discriminant in a while loop (or with recursion) to know if I need to keep calling decodeURIComponent on the string:

function fullyDecodeURI(uri){

  while (isEncoded(uri)){
    uri = decodeURIComponent(uri);
  }

  return uri;
}

This solved the problem for me of decoding urls encoded multiple times. Hope this helps.

rodu
  • 2,308
  • 3
  • 15
  • 6
  • Thx, helped me alot :) – Steffan May 31 '17 at 19:32
  • 6
    Still doesn't work if your decoded url has a %20 in the filename or something. – Chet Aug 07 '18 at 02:00
  • 1 line version: `const isEncoded = uri => uri !== decodeURIComponent(uri || '')` – Daniel Tonon Jul 16 '20 at 00:37
  • Nice function! As a string could contain a "normal" percent sign, decodeURIComponent will trigger and error which you can catch. Which could mean the string is unencoded, so that would be a nice addition to this – LaVomit Aug 11 '22 at 08:50
15

Repeatedly decoding until you find no % signs will work over 99% of the time. It'll work even better if you repeatedly call so long as a match for /%[0-9a-f]{2}/i can be found.

However, if I were (for some bizarre reason) to name a file 100%achieved, that would cause a problem because %ac would be decoded to ¬, causing the decode to fail. Unfortunately there's no way to detect this case.

Ideally you should know if something is encoded more than once, and optimally you shouldn't let it happen in the first place.

Niet the Dark Absol
  • 320,036
  • 81
  • 464
  • 592
  • By repeatedly decoding you mean a recursive call? – Tapas Bose Jul 10 '13 at 07:57
  • No, I mean a `do..while` loop. – Niet the Dark Absol Jul 10 '13 at 07:59
  • I will give a try to the `do..while`, however I have written a recursion in my Update - 3. Please take a look. – Tapas Bose Jul 10 '13 at 08:04
  • 1
    I don't like recursive functions in general, because it is extremely easy to get stuck in an infinite loop and blow up the call stack. On the other hand, an infinite `do..while` loop will cause the browser to hang/crash, but at least it won't consume all the available memory before doing so. – Niet the Dark Absol Jul 10 '13 at 08:05
  • What I do is simply to search for **space ( )**,**line-breaks (\n)**, **carriage-return (\r)** and **tag (\t)** characters. In my case I want to execute a JavaScript via the browsers address bar. `javascript:alert('test string')` so it is sufficient for me. – Yoraco Gonzales May 25 '15 at 17:48
1
function checkEncodeURI(str) {
 return /\%/i.test(str)
}

Test :

let url1 = "https://quora.com/unanswered/I’m-looking-for-a-Freaks-And-Friends-Fox-Glitter-Face-Hinge-Wallet-for-a-Christmas-gift-I’ve-searched-for-hours-online-but-no-one-seemed-to-have-it-does-anyone-know-where-I-can-find-one"
let url2 = 'https://www.quora.com/unanswered/I%E2%80%99m-looking-for-a-Freaks-And-Friends-Fox-Glitter-Face-Hinge-Wallet-for-a-Christmas-gift-I%E2%80%99ve-searched-for-hours-online-but-no-one-seemed-to-have-it-does-anyone-know-where-I-can-find-one'
let a = checkEncodeURI(url1)
console.log(a)
let b = checkEncodeURI(url2)
console.log(b)
Manishh
  • 1,444
  • 13
  • 23
0

you can keep decode until the string did not change:

str = "xxxxxxx"
dec_str = decode(str)
while(dec_str != str)
     str = dec_str;
     dec_str = decode(str);
0

There is really simple and fast and trusted way to know if a URL string is encoded or Not.

For Example: decodeURIComponent(decodeURIComponent(encodeURIComponent("SWQgPSA0NjI%3D"))) <> "SWQgPSA0NjI=" ----> Not equal to orginal value then Already encoded

just this code:

  var encValue = encodeURIComponent(Value);
    try {
         if (decodeURIComponent(decodeURIComponent(encValue)) === Value) {
          //not encodec yet...so return encoded of val
          return encValue;
         }
       } catch (err) {
           //not encodec yet...so return encoded of val
           return encValue;
       }

 return Value  //same value returned

                        
saber.w
  • 1
  • 1
  • 3
0

I found this helpful when I was experiencing a similar issue. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent

function containsEncodedComponents(x) {
  // ie ?,=,&,/ etc
  return (decodeURI(x) !== decodeURIComponent(x));
}

console.log(containsEncodedComponents('%3Fx%3Dtest')); // ?x=test
// Expected output: true

console.log(containsEncodedComponents('%D1%88%D0%B5%D0%BB%D0%BB%D1%8B')); // шеллы
// Expected output: false
  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jul 23 '23 at 14:04