7003155: (fs) Paths.get(<file-uri>) does not handle escaped octets correctly
Reviewed-by: sherman
--- a/jdk/src/solaris/classes/sun/nio/fs/UnixUriUtils.java Mon Feb 07 13:53:36 2011 +0000
+++ b/jdk/src/solaris/classes/sun/nio/fs/UnixUriUtils.java Mon Feb 07 13:55:40 2011 +0000
@@ -25,8 +25,11 @@
package sun.nio.fs;
+import java.nio.file.Path;
+import java.io.File;
import java.net.URI;
import java.net.URISyntaxException;
+import java.util.Arrays;
/**
* Unix specific Path <--> URI conversion
@@ -38,7 +41,7 @@
/**
* Converts URI to Path
*/
- static UnixPath fromUri(UnixFileSystem fs, URI uri) {
+ static Path fromUri(UnixFileSystem fs, URI uri) {
if (!uri.isAbsolute())
throw new IllegalArgumentException("URI is not absolute");
if (uri.isOpaque())
@@ -53,22 +56,41 @@
if (uri.getQuery() != null)
throw new IllegalArgumentException("URI has a query component");
- String path = uri.getPath();
- if (path.equals(""))
+ // compatability with java.io.File
+ if (!uri.toString().startsWith("file:///"))
+ return new File(uri).toPath();
+
+ // transformation use raw path
+ String p = uri.getRawPath();
+ int len = p.length();
+ if (len == 0)
throw new IllegalArgumentException("URI path component is empty");
- if (path.endsWith("/") && (path.length() > 1)) {
- // "/foo/" --> "/foo", but "/" --> "/"
- path = path.substring(0, path.length() - 1);
- }
- // preserve bytes
- byte[] result = new byte[path.length()];
- for (int i=0; i<path.length(); i++) {
- byte v = (byte)(path.charAt(i));
- if (v == 0)
- throw new IllegalArgumentException("Nul character not allowed");
- result[i] = v;
+ // transform escaped octets and unescaped characters to bytes
+ if (p.endsWith("/") && len > 1)
+ len--;
+ byte[] result = new byte[len];
+ int rlen = 0;
+ int pos = 0;
+ while (pos < len) {
+ char c = p.charAt(pos++);
+ byte b;
+ if (c == '%') {
+ assert (pos+2) <= len;
+ char c1 = p.charAt(pos++);
+ char c2 = p.charAt(pos++);
+ b = (byte)((decode(c1) << 4) | decode(c2));
+ if (b == 0)
+ throw new IllegalArgumentException("Nul character not allowed");
+ } else {
+ assert c < 0x80;
+ b = (byte)c;
+ }
+ result[rlen++] = b;
}
+ if (rlen != result.length)
+ result = Arrays.copyOf(result, rlen);
+
return new UnixPath(fs, result);
}
@@ -86,7 +108,7 @@
} else {
sb.append('%');
sb.append(hexDigits[(c >> 4) & 0x0f]);
- sb.append(hexDigits[(c >> 0) & 0x0f]);
+ sb.append(hexDigits[(c) & 0x0f]);
}
}
@@ -164,6 +186,17 @@
return false;
}
+ // decode
+ private static int decode(char c) {
+ if ((c >= '0') && (c <= '9'))
+ return c - '0';
+ if ((c >= 'a') && (c <= 'f'))
+ return c - 'a' + 10;
+ if ((c >= 'A') && (c <= 'F'))
+ return c - 'A' + 10;
+ throw new AssertionError();
+ }
+
// digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" |
// "8" | "9"
private static final long L_DIGIT = lowMask('0', '9');
--- a/jdk/test/java/nio/file/Path/UriImportExport.java Mon Feb 07 13:53:36 2011 +0000
+++ b/jdk/test/java/nio/file/Path/UriImportExport.java Mon Feb 07 13:55:40 2011 +0000
@@ -22,7 +22,7 @@
*/
/* @test
- * @bug 4313887
+ * @bug 4313887 7003155
* @summary Unit test for java.nio.file.Path
*/
@@ -36,42 +36,105 @@
static final PrintStream log = System.out;
static int failures = 0;
- static void test(String fn, String expected) {
+ /**
+ * Test Path -> URI -> Path
+ */
+ static void testPath(String s) {
+ Path path = Paths.get(s);
+ log.println(path);
+ URI uri = path.toUri();
+ log.println(" --> " + uri);
+ Path result = Paths.get(uri);
+ log.println(" --> " + result);
+ if (!result.equals(path.toAbsolutePath())) {
+ log.println("FAIL: Expected " + path + ", got " + result);
+ failures++;
+ }
log.println();
- Path p = Paths.get(fn);
- log.println(p);
- URI u = p.toUri();
- log.println(" --> " + u);
- if (expected != null && !(u.toString().equals(expected))) {
- log.println("FAIL: Expected " + expected);
- failures++;
- return;
- }
- Path q = Paths.get(u);
- log.println(" --> " + q);
- if (!p.toAbsolutePath().equals(q)) {
- log.println("FAIL: Expected " + p + ", got " + q);
+ }
+
+ /**
+ * Test Path -> (expected) URI -> Path
+ */
+ static void testPath(String s, String expectedUri) {
+ Path path = Paths.get(s);
+ log.println(path);
+ URI uri = path.toUri();
+ log.println(" --> " + uri);
+ if (!uri.toString().equals(expectedUri)) {
+ log.println("FAILED: Expected " + expectedUri + ", got " + uri);
failures++;
return;
}
+ Path result = Paths.get(uri);
+ log.println(" --> " + result);
+ if (!result.equals(path.toAbsolutePath())) {
+ log.println("FAIL: Expected " + path + ", got " + result);
+ failures++;
+ }
+ log.println();
}
- static void test(String fn) {
- test(fn, null);
+ /**
+ * Test URI -> Path -> URI
+ */
+ static void testUri(String s) throws Exception {
+ URI uri = URI.create(s);
+ log.println(uri);
+ Path path = Paths.get(uri);
+ log.println(" --> " + path);
+ URI result = path.toUri();
+ log.println(" --> " + result);
+ if (!result.equals(uri)) {
+ log.println("FAIL: Expected " + uri + ", got " + result);
+ failures++;
+ }
+ log.println();
+ }
+
+ /**
+ * Test URI -> Path fails with IllegalArgumentException
+ */
+ static void testBadUri(String s) throws Exception {
+ URI uri = URI.create(s);
+ log.println(uri);
+ try {
+ Path path = Paths.get(uri);
+ log.format(" --> %s FAIL: Expected IllegalArgumentException\n", path);
+ failures++;
+ } catch (IllegalArgumentException expected) {
+ log.println(" --> IllegalArgumentException (expected)");
+ }
+ log.println();
}
public static void main(String[] args) throws Exception {
- test("foo");
- test("/foo");
- test("/foo bar");
+ testBadUri("file:foo");
+ testBadUri("file:/foo?q");
+ testBadUri("file:/foo#f");
String osname = System.getProperty("os.name");
if (osname.startsWith("Windows")) {
- test("C:\\foo");
- test("C:foo");
- test("\\\\rialto.dublin.com\\share\\");
- test("\\\\fe80--203-baff-fe5a-749ds1.ipv6-literal.net\\share\\missing",
+ testPath("C:\\doesnotexist");
+ testPath("C:doesnotexist");
+ testPath("\\\\server.nowhere.oracle.com\\share\\");
+ testPath("\\\\fe80--203-baff-fe5a-749ds1.ipv6-literal.net\\share\\missing",
"file://[fe80::203:baff:fe5a:749d%1]/share/missing");
+ } else {
+ testPath("doesnotexist");
+ testPath("/doesnotexist");
+ testPath("/does not exist");
+ testUri("file:///");
+ testUri("file:///foo/bar/doesnotexist");
+ testUri("file:/foo/bar/doesnotexist");
+
+ // file:///foo/bar/\u0440\u0443\u0441\u0441\u043A\u0438\u0439 (Russian)
+ testUri("file:///foo/bar/%D1%80%D1%83%D1%81%D1%81%D0%BA%D0%B8%D0%B9");
+
+ // invalid
+ testBadUri("file:foo");
+ testBadUri("file://server/foo");
+ testBadUri("file:///foo%00");
}
if (failures > 0)