1
  • I have some legacy code (pre-React) that encodes part of a URL with encodeURIComponent before calling history.push() on the https://www.npmjs.com/package/history module in order to navigate to that URL.
  • history.push() inside history.js then uses decodeURI to decode the entire URL partially (decodeURI only decodes the same characters that encodeURI encodes)
  • this partially decoded location.pathname ends up in ReactRouter where useParams() gives me the partially decoded URL component back again.

Now I'm stuck with a partially decoded URL component which I cannot use. I need it fully decoded.

I can't use decodeURIComponent on the partially decoded string, because the original string might contain a %, in which case this % will already be decoded in the partially decoded string and this would cause decodeURIComponent to crash with a Uncaught URIError: URI malformed.

My options seem to be:

  • use unescape to fully decode the partially decoded string (it doesn't complain about the single %) even though its use is discouraged (why?)
  • manually re-encode any % (that isn't followed by a digit and a subsequent hex character) back to %25 and then run the result through decodeURIComponent

Are there any less ugly solutions that I haven't thought of yet ?

EDIT : I was asked for examples of what I meant by partially decided string

const original = 'A-Za-z0-9;,/?:@&=+$-_.!~*()#%';
const encodedURIComponent = encodeURIComponent(original); // "A-Za-z0-9%3B%2C%2F%3F%3A%40%26%3D%2B%24-_.!~*()%23%25"
console.log(decodeURIComponent(encodedURIComponent)); //  "A-Za-z0-9;,/?:@&=+$-_.!~*()#%"
const partiallyUnescaped = decodeURI(encodedURIComponent); // "A-Za-z0-9%3B%2C%2F%3F%3A%40%26%3D%2B%24-_.!~*()%23%" - notice the '%25' at the end was decoded back to '%'
console.log(unescape(partiallyUnescaped)); // "A-Za-z0-9;,/?:@&=+$-_.!~*()#%"
//console.log(decodeURIComponent(partiallyUnescaped)); // error

EDIT 2: In case it can be of any help, here's a more realistic example of some of the characters our URL might contain, but because it's user generated, it could be anything really:

  console.log(                             encodeURIComponent('abcd+%;- efgh'))  ; // "abcd%2B%25%3B-%20efgh"
  console.log(                   decodeURI(encodeURIComponent('abcd+%; -efgh'))) ; // "abcd%2B%%3B- efgh"
//console.log(decodeURIComponent(decodeURI(encodeURIComponent('abcd+%; -efgh')))); // Error: URI malformed
Chris
  • 4,212
  • 5
  • 37
  • 52
  • 1
    Not sure what you mean by 'partially'. Can you show an example? – apena Aug 29 '20 at 01:19
  • 2
    Unfortunately, I don't think this is possible. I think the string becomes ambiguous, doesn't it? – Brad Aug 29 '20 at 01:26
  • @apena I added an example I had at hand ... maybe not the best, but I hope it shows the main problem with the decoded '%' sign. – Chris Aug 29 '20 at 23:31
  • 1
    `unescape` or a manual decoder wouldn't help either, imagine your input contains literally `%25`, encodedURIComponent would make it `%2525`, then `decodeURI` would make it `%25` and finally `unescape` would convert it to `%`, losing the original `%25`. Now, can you please clarify what parts of the URL your "legacy code" is encoding? That's what you need to fix so it encodes correctly only the parts required. (note: looking at the lib's repo, [they seem to have fixed related issues](https://github.com/ReactTraining/history/pull/790/commits/815014857624e9d00a6b8c213aa86ada4814a51e) – Kaiido Aug 30 '20 at 03:00

0 Answers0