kotlin

Are there two URL objects whose equality is false but whose toString is the same?


Are there two URL (from java.net.URL) objects whose equality is false but whose toString is the same?

val url1 = ...
val url2 = ...
println(url1 == url2) // should print false
printnln(url1.toString() == url2.toString()) // should print true

The opposite is much easier

val u1: URL = java.net.URL("http://example.com/path")
val u2: URL = java.net.URL("http://example.com:80/path") // explicit default port
println(url1 == url2) // prints true
printnln(url1.toString() == url2.toString()) // prints false

For context, I'm migrating from old way to do URLs via URL(string) to new way using URI and I see these cases in the logs, but then the toString is the same.

My theory is that URL equals performs a DNS check for both URLs. So if there were to be an IP change in between the host check, it would not be equal.


Solution

  • So the following simple code can already fail:

    val urla = "http://oracle.com"
    val url1 = URL(urla)
    val url2 = URL(urla)
    assertTrue(url1 == url2)
    

    In order to reproduce it, I prepare two files

    cat /etc/hosts.with_overrides
    > ## contains
    > 127.0.0.1 oracle.com
    

    And

    
    cat /etc/hosts.no_overrides
    > # normal file
    

    I set a debugger in UrlStreamHandler, at

    protected boolean hostsEqual(URL u1, URL u2) {
        InetAddress a1 = getHostAddress(u1);
        InetAddress a2 = getHostAddress(u2);
    

    I let the first resolution happen, then

    
    sudo cp /etc/hosts.with_overrides /etc/hosts
    

    or the other way around. Wait for some time for cache to clean up. I run a line and now I see:

    enter image description here

    And the assert fails.

    In production with more volume, this happens quite often.