7171415: java.net.URI.equals/hashCode not consistent for some URIs
authorkhazra
Thu, 17 Jan 2013 14:50:02 -0800
changeset 15272 b0055428d835
parent 15271 570508dfed48
child 15273 fc0a33508cf7
7171415: java.net.URI.equals/hashCode not consistent for some URIs Summary: Rewrite URI.hashCode() to consider encoded characters, also reviewed by vitalyd@gmail.com, schlosna@gmail.com Reviewed-by: chegar
jdk/src/share/classes/java/net/URI.java
jdk/test/java/net/URI/Test.java
--- a/jdk/src/share/classes/java/net/URI.java	Thu Jan 17 12:49:33 2013 -0800
+++ b/jdk/src/share/classes/java/net/URI.java	Thu Jan 17 14:50:02 2013 -0800
@@ -1694,6 +1694,13 @@
         return c;
     }
 
+    // US-ASCII only
+    private static int toUpper(char c) {
+        if ((c >= 'a') && (c <= 'z'))
+            return c - ('a' - 'A');
+        return c;
+    }
+
     private static boolean equal(String s, String t) {
         if (s == t) return true;
         if ((s != null) && (t != null)) {
@@ -1744,7 +1751,26 @@
 
     private static int hash(int hash, String s) {
         if (s == null) return hash;
-        return hash * 127 + s.hashCode();
+        return s.indexOf('%') < 0 ? hash * 127 + s.hashCode()
+                                  : normalizedHash(hash, s);
+    }
+
+
+    private static int normalizedHash(int hash, String s) {
+        int h = 0;
+        for (int index = 0; index < s.length(); index++) {
+            char ch = s.charAt(index);
+            h = 31 * h + ch;
+            if (ch == '%') {
+                /*
+                 * Process the next two encoded characters
+                 */
+                for (int i = index + 1; i < index + 3; i++)
+                    h = 31 * h + toUpper(s.charAt(i));
+                index += 2;
+            }
+        }
+        return hash * 127 + h;
     }
 
     // US-ASCII only
--- a/jdk/test/java/net/URI/Test.java	Thu Jan 17 12:49:33 2013 -0800
+++ b/jdk/test/java/net/URI/Test.java	Thu Jan 17 14:50:02 2013 -0800
@@ -24,6 +24,7 @@
 /* @test
  * @summary Unit test for java.net.URI
  * @bug 4464135 4505046 4503239 4438319 4991359 4866303 7023363 7041800
+ *      7171415
  * @author Mark Reinhold
  */
 
@@ -1337,7 +1338,7 @@
     }
 
 
-    static void eq0(Comparable u, Comparable v) throws URISyntaxException {
+    static void eq0(URI u, URI v) throws URISyntaxException {
         testCount++;
         if (!u.equals(v))
             throw new RuntimeException("Not equal: " + u + " " + v);
@@ -1352,7 +1353,7 @@
                     + "  [" + Integer.toHexString(uh) + "]");
     }
 
-    static void cmp0(Comparable u, Comparable v, boolean same)
+    static void cmp0(URI u, URI v, boolean same)
         throws URISyntaxException
     {
         int c = u.compareTo(v);
@@ -1361,18 +1362,18 @@
                                        + " " + c);
     }
 
-    static void eq(Comparable u, Comparable v) throws URISyntaxException {
+    static void eq(URI u, URI v) throws URISyntaxException {
         eq0(u, v);
         cmp0(u, v, true);
     }
 
-    static void eqeq(Comparable u, Comparable v) {
+    static void eqeq(URI u, URI v) {
         testCount++;
         if (u != v)
             throw new RuntimeException("Not ==: " + u + " " + v);
     }
 
-    static void ne0(Comparable u, Comparable v) throws URISyntaxException {
+    static void ne0(URI u, URI v) throws URISyntaxException {
         testCount++;
         if (u.equals(v))
             throw new RuntimeException("Equal: " + u + " " + v);
@@ -1383,17 +1384,17 @@
                     + "]");
     }
 
-    static void ne(Comparable u, Comparable v) throws URISyntaxException {
+    static void ne(URI u, URI v) throws URISyntaxException {
         ne0(u, v);
         cmp0(u, v, false);
     }
 
-    static void lt(Comparable u, Comparable v) throws URISyntaxException {
+    static void lt(URI u, URI v) throws URISyntaxException {
         ne0(u, v);
         int c = u.compareTo(v);
         if (c >= 0) {
-            show((URI)u);
-            show((URI)v);
+            show(u);
+            show(v);
             throw new RuntimeException("Not less than: " + u + " " + v
                                        + " " + c);
         }
@@ -1404,7 +1405,7 @@
         lt(new URI(s), new URI(t));
     }
 
-    static void gt(Comparable u, Comparable v) throws URISyntaxException {
+   static void gt(URI u, URI v) throws URISyntaxException {
         lt(v, u);
     }
 
@@ -1430,6 +1431,8 @@
         lt(s, new URI("http://jag:cafebabe@java.sun.com:94/b/c/d?q#g"));
         eq(new URI("http://host/a%00bcd"), new URI("http://host/a%00bcd"));
         ne(new URI("http://host/a%00bcd"), new URI("http://host/aZ00bcd"));
+        eq0(new URI("http://host/abc%e2def%C3ghi"),
+            new URI("http://host/abc%E2def%c3ghi"));
 
         lt("p", "s:p");
         lt("s:p", "T:p");
@@ -1465,7 +1468,7 @@
         ObjectInputStream oi = new ObjectInputStream(bi);
         try {
             Object o = oi.readObject();
-            eq(u, (Comparable)o);
+            eq(u, (URI)o);
         } catch (ClassNotFoundException x) {
             x.printStackTrace();
             throw new RuntimeException(x.toString());