Pacharapol Withayasakpunt Pacharapol Withayasakpunt
Tue, July 14, 2020

encodeURIComponent is both not safe enough, and overdone

I have tested with encodeURIComponent, decodeURIComponent and URL constructor, and the results are

{
  "pathname": {
    "destroyed": " #.?",
    "encoded": "\"<>`{}",
    "error": {
      "Invalid URL: //": "/",
      "Invalid URL: /\\": "\\"
    }
  },
  "key": {
    "destroyed": "#&+="
  },
  "value": {
    "destroyed": " #&+"
  },
  "hash": {
    "destroyed": " ",
    "encoded": "\"<>`"
  },
  // /[A-Za-z0-9]/ are excluded.
  "notEncoded": {
    "encodeURI": "!#$&'()*+,-./:;=?@_~",
    "encodeURIComponent": "!'()*-._~",
    "escape": "*+-./@_"
  }
  // encoded with `%${x.charCodeAt(0).toString(16).toUpperCase()}`
  "notDecoded": {
    "decodeURI": "#$&+,/:;=?@"
  }
}

The test is here.

So,

  • Reserved characters ;,/?:@&=+$ are not equal. Some are allowed in some scenarios, some are not. And it seems that encodeURI is never safe to encode a URI segment.
  • Path params, e.g. /:segment/* on the server
    • ., .. always have wrong meanings, whether percent-encoded or not. And encodeURIComponent('.') is indeed .. /^\.{3,}$/ are ok, though.
    • It seems that escaping by prefixing with ~ is enough.
    • /, even when encoded, may throw error on some server. Not sure about \, but it seems to throw error in my test.
  • Luckily, these are always encoded. I have seen a recent post about the errors.
"<>`{}

https://dev.to/antho1404/encoding-mess-with-javascript-oan

  • Not sure if non-ASCII (/[^\x00-\x7F]/) needs to be encoded. You can try it in my demo, and see if it breaks.

https://encodeuri-plus.netlify.app/

So, I created a library for this,

https://github.com/patarapolw/encodeuri-plus