javascripthtmlwindow.location

Inconsistent behavior of the URL constructor between Safari and Chrome, when working with custom URL schema


I am trying to figure out why there is a difference between two identical URL constructor calls in Safari and Chrome

Here is the example from Safari:

Safari

And here is an example from Chrome:

Chrome

I'm working on an application that embeds inside a webview for various mobile platforms such as Android and Ios. This behavior of the URL constructor creates problems.

As you can in the chrome pathname includes localhost which is incorrect, the hostname and host are also empty, in safari everything seems fine

I was trying to set up manifest.json locally to test is there a way to control this behavior by registering custom URL schema, also I was trying to play with navigator.registerProtocolHandler, here is the link to the docs.


Solution

  • This is not really a problem with the URL constructor. The problem is actually with the argument that has been provided to the constructor.

    As you probably already know, JavaScript is quite a hacky language. Rather than being very strict and uptight, it tries to handle everything as gracefully as possible rather than throwing an exception (that's why we have tons of terrible JavaScript developers).

    First: test is not an actual protocol

    The first issue is that test:// is not an actually a protocol. However, the URL constructor doesn't really care because people make up new protocols every single day. Because of this, URL will accept test:// as a valid protocol

    Second: Hostname is incorrect

    This is where the difference between a URI and a URL come into play. A URI can have any format as the hostname (after the protocol, ://, and before the path, /).

    With a URL, the hostname must contain the domain name (google) and the top-level domain (.com). There are some URLs, like yours, that don't include a top-level domain. In the case that you are using localhost, you should also include a port number (:3000 or :8080 or something like that).


    If you try the following, then you will notice that they have identical implementations:

    new URL('https://localhost:3000/my/path?query=my+query')