58

The SO post below is comprehensive, but all three methods described fail to encode for periods.

Post: Encode URL in JavaScript?

For instance, if I run the three methods (i.e., escape, encodeURI, encodeURIComponent), none of them encode periods.

So "food.store" comes out as "food.store," which breaks the URL. It breaks the URL because the Rails app cannot recognize the URL as valid and displays the 404 error page. Perhaps it's a configuration mistake in the Rails routes file?

What's the best way to encode periods with Javascript for URLs?

Community
  • 1
  • 1
Crashalot
  • 33,605
  • 61
  • 269
  • 439
  • 8
    In what way does it break the URL? Periods do not have to be encoded as far as I know. – igorw Feb 08 '11 at 21:55
  • Thanks, updated the question to reflect your question. – Crashalot Feb 11 '11 at 01:16
  • I added "ruby-on-rails" to your tags - this is not a general URL problem, but either a Rails problem or something specific to your application. – Pointy Feb 11 '11 at 01:40
  • Another valid reason for escaping periods is the url selector in Apache Sling (used by Day CQ): http://sling.apache.org/documentation/the-sling-engine/url-decomposition.html – T. Junghans Jul 09 '13 at 08:03
  • For those with a broken page using vite: https://github.com/vitejs/vite/issues/2415 – spencer.sm Jul 26 '23 at 15:27

9 Answers9

70

I know this is an old thread, but I didn't see anywhere here any examples of URLs that were causing the original problem. I encountered a similar problem myself a couple of days ago with a Java application. In my case, the string with the period was at the end of the path element of the URL eg.

http://myserver.com/app/servlet/test.string

In this case, the Spring library I'm using was only passing me the 'test' part of that string to the relevant annotated method parameter of my controller class, presumably because it was treating the '.string' as a file extension and stripping it away. Perhaps this is the same underlying issue with the original problem above?

Anyway, I was able to workaround this simply by adding a trailing slash to the URL. Just throwing this out there in case it is useful to anybody else.

John

John Rix
  • 6,271
  • 5
  • 40
  • 46
  • 2
    Hmm, this didn't work using rails 3.2; the trailing slash gets eaten first (before the period and following "type" get stripped off. Any ideas? – Cory Kendall Jun 11 '14 at 18:35
36

Periods shouldn't break the url, but I don't know how you are using the period, so I can't really say. None of the functions I know of encode the '.' for a url, meaning you will have to use your own function to encode the '.' .

You could base64 encode the data, but I don't believe there is a native way to do that in js. You could also replace all periods with their ASCII equivalent (%2E) on both the client and server side.

Basically, it's not generally necessary to encode '.', so if you need to do it, you'll need to come up with your own solution. You may want to also do further testing to be sure the '.' will actually break the url.

hth

superultranova
  • 1,294
  • 8
  • 14
  • 2
    @crashalot I think your Rails routing configuration needs to be fixed. I'm not a rails guy, but it is possible Rails doesn't support periods. Check out this url, I believe it addresses your problem: http://masonoise.wordpress.com/2010/02/04/rails-routes-with-string-ids-and-periods/ – superultranova Feb 11 '11 at 01:51
  • I wasn't able to find my routes so used this hacky crappy work around: Tag.find_by_name(params[:id] + '.' + params[:format]) – rogerdpack Sep 06 '12 at 00:22
  • Yes, you can natively encode with base64 in javascript with atob and btoa. Not that I would recommend it for URL parameters... – wedstrom Aug 15 '17 at 22:21
  • Actually paypal encodes the return url dot. "website.com" is converted to "website%2ecom". You can do it from here https://www.paypal.com/uk/cgi-bin/webscr?cmd=_button-management (add a return url, don't save button in paypal and then look at the email version of the link) – Totty.js Sep 17 '18 at 03:08
15

I had this same problem where my .htaccess was breaking input values with . Since I did not want to change what the .htaccess was doing I used this to fix it:

var val="foo.bar";
var safevalue=encodeURIComponent(val).replace(/\./g, '%2E');

this does all the standard encoding then replaces . with there ascii equivalent %2E. PHP automatically converts back to . in the $_REQUEST value but the .htaccess doesn't see it as a period so things are all good.

  • 6
    Javascript escape() will also convert %2E back to the original period; this is the best, most direct answer. – mmmpop Apr 26 '17 at 00:55
  • 1
    For URLs encoded in this fashion on a sever rendered page at least, browsers decode the encoded periods back before you follow the links, so this doesn't solve the problem in many cases. – John Rix Aug 03 '17 at 00:50
7

Periods do not have to be encoded in URLs. Here is the RFC to look at.

If a period is "breaking" something, it may be that your server is making its own interpretation of the URL, which is a fine thing to do of course but it means that you have to come up with some encoding scheme of your own when your own metacharacters need escaping.

Community
  • 1
  • 1
Pointy
  • 405,095
  • 59
  • 585
  • 614
  • Sole `/.`, `/..`, `/%2E`, `/%2E%2E` can all break `URL` constructor, with browser JavaScript alone. – Polv Jul 15 '20 at 22:19
  • @Polv as I wrote in the answer, a period may be *wrong* based on how a server works and/or an application on the server, but they do not need to be encoded in order for the URL itself to be syntactically correct. – Pointy Jul 15 '20 at 23:34
5

I had the same question and maybe my solution can help someone else in the future.

In my case the url was generated using javascript. Periods are used to separate values in the url (sling selectors), so the selectors themselves weren't allowed to have periods.

My solution was to replace all periods with the html entity as is Figure 1:

Figure 1: Solution

var urlPart = 'foo.bar';
var safeUrlPart = encodeURIComponent(urlPart.replace(/\./g, '.'));

console.log(safeUrlPart); // foo%26%2346%3Bbar
console.log(decodeURIComponent(safeUrlPart)); // foo.bar
T. Junghans
  • 11,385
  • 7
  • 52
  • 75
2

I had problems with .s in rest api urls. It is the fact that they are interpreted as extensions which in it's own way makes sense. Escaping doesn't help because they are unescaped before the call (as already noted). Adding a trailing / didn't help either. I got around this by passing the value as a named argument instead. e.g. api/Id/Text.string to api/Id?arg=Text.string. You'll need to modify the routing on the controller but the handler itself can stay the same.

1

If its possible using a .htaccess file would make it really cool and easy. Just add a \ before the period. Something like:\.

David Lartey
  • 531
  • 8
  • 15
0

It is a rails problem, see Rails REST routing: dots in the resource item ID for an explanation (and Rails routing guide, Sec. 3.2)

Community
  • 1
  • 1
user1251840
  • 655
  • 5
  • 8
0

You shouldn't be using encodeURI() or encodeURIComponent() anyway.

console.log(encodeURIComponent('%^&*'));

Input: %^&*. Output: %25%5E%26*. So, to be clear, this doesn't convert *. Hopefully you know this before you run rm * after "cleansing" that input server-side!

Luckily, MDN gave us a work-around to fix this glaring problem, fixedEncodeURI() and fixedEncodeURIComponent(), which is based on this regex: [!'()*]. (Source: MDN Web Docs: encodeURIComponent().) Just rewrite it to add in a period and you'll be fine:

function fixedEncodeURIComponent(str) {
 return encodeURIComponent(str).replace(/[\.!'()*]/g, function(c) {
   return '%' + c.charCodeAt(0).toString(16);
 });
}

console.log(fixedEncodeURIComponent('hello.'));
HoldOffHunger
  • 18,769
  • 10
  • 104
  • 133