8037396: URI getQuery() and getFragment() don't decode properly
authormichaelm
Mon, 07 Apr 2014 15:40:05 +0100
changeset 23725 0190e5c0e70c
parent 23724 c35574e21791
child 23726 2f18b12acbdf
child 23729 9567adf703ec
8037396: URI getQuery() and getFragment() don't decode properly Reviewed-by: chegar, michaelm Contributed-by: pavel.reppo@oracle.com
jdk/src/share/classes/java/net/URI.java
jdk/test/java/net/URI/Test.java
--- a/jdk/src/share/classes/java/net/URI.java	Mon Apr 07 13:16:17 2014 +0100
+++ b/jdk/src/share/classes/java/net/URI.java	Mon Apr 07 15:40:05 2014 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -1337,7 +1337,7 @@
      */
     public String getQuery() {
         if ((decodedQuery == null) && (query != null))
-            decodedQuery = decode(query);
+            decodedQuery = decode(query, false);
         return decodedQuery;
     }
 
@@ -1366,7 +1366,7 @@
      */
     public String getFragment() {
         if ((decodedFragment == null) && (fragment != null))
-            decodedFragment = decode(fragment);
+            decodedFragment = decode(fragment, false);
         return decodedFragment;
     }
 
@@ -2764,6 +2764,12 @@
     //            with a scope_id
     //
     private static String decode(String s) {
+        return decode(s, true);
+    }
+
+    // This method was introduced as a generalization of URI.decode method
+    // to provide a fix for JDK-8037396
+    private static String decode(String s, boolean ignorePercentInBrackets) {
         if (s == null)
             return s;
         int n = s.length();
@@ -2776,8 +2782,8 @@
         ByteBuffer bb = ByteBuffer.allocate(n);
         CharBuffer cb = CharBuffer.allocate(n);
         CharsetDecoder dec = ThreadLocalCoders.decoderFor("UTF-8")
-            .onMalformedInput(CodingErrorAction.REPLACE)
-            .onUnmappableCharacter(CodingErrorAction.REPLACE);
+                .onMalformedInput(CodingErrorAction.REPLACE)
+                .onUnmappableCharacter(CodingErrorAction.REPLACE);
 
         // This is not horribly efficient, but it will do for now
         char c = s.charAt(0);
@@ -2790,7 +2796,7 @@
             } else if (betweenBrackets && c == ']') {
                 betweenBrackets = false;
             }
-            if (c != '%' || betweenBrackets) {
+            if (c != '%' || (betweenBrackets && ignorePercentInBrackets)) {
                 sb.append(c);
                 if (++i >= n)
                     break;
--- a/jdk/test/java/net/URI/Test.java	Mon Apr 07 13:16:17 2014 +0100
+++ b/jdk/test/java/net/URI/Test.java	Mon Apr 07 15:40:05 2014 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -1367,6 +1367,17 @@
         cmp0(u, v, true);
     }
 
+    static void eq(String expected, String actual) {
+        if (expected == null && actual == null) {
+            return;
+        }
+        if (expected != null && expected.equals(actual)) {
+            return;
+        }
+        throw new AssertionError(String.format(
+                "Strings are not equal: '%s', '%s'", expected, actual));
+    }
+
     static void eqeq(URI u, URI v) {
         testCount++;
         if (u != v)
@@ -1588,7 +1599,12 @@
     // miscellaneous bugs/rfes that don't fit in with the test framework
 
     static void bugs() {
-        // 6339649 - include detail message from nested exception
+        b6339649();
+        b8037396();
+    }
+
+    // 6339649 - include detail message from nested exception
+    private static void b6339649() {
         try {
             URI uri = URI.create("http://nowhere.net/should not be permitted");
         } catch (IllegalArgumentException e) {
@@ -1598,6 +1614,39 @@
         }
     }
 
+    private static void b8037396() {
+
+        // primary checks:
+
+        URI u;
+        try {
+            u = new URI("http", "example.org", "/[a b]", "[a b]", "[a b]");
+        } catch (URISyntaxException e) {
+            throw new AssertionError("shouldn't ever happen", e);
+        }
+        eq("/[a b]", u.getPath());
+        eq("[a b]", u.getQuery());
+        eq("[a b]", u.getFragment());
+
+        // additional checks:
+        //  *   '%' symbols are still decoded outside square brackets
+        //  *   the getRawXXX() functionality left intact
+
+        try {
+            u = new URI("http", "example.org", "/a b[c d]", "a b[c d]", "a b[c d]");
+        } catch (URISyntaxException e) {
+            throw new AssertionError("shouldn't ever happen", e);
+        }
+
+        eq("/a b[c d]", u.getPath());
+        eq("a b[c d]", u.getQuery());
+        eq("a b[c d]", u.getFragment());
+
+        eq("/a%20b%5Bc%20d%5D", u.getRawPath());
+        eq("a%20b[c%20d]", u.getRawQuery());
+        eq("a%20b[c%20d]", u.getRawFragment());
+    }
+
     public static void main(String[] args) throws Exception {
         switch (args.length) {