8131067: (zipfs) Zip File System Provider returns doubly-encoded Path URIs
Summary: to decode the zip file path uri before passing it into zippath uri.
Reviewed-by: alanb
--- a/jdk/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystemProvider.java Thu Aug 27 13:22:51 2015 -0700
+++ b/jdk/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystemProvider.java Thu Aug 27 14:32:42 2015 -0700
@@ -65,8 +65,9 @@
// only support legacy JAR URL syntax jar:{uri}!/{entry} for now
String spec = uri.getRawSchemeSpecificPart();
int sep = spec.indexOf("!/");
- if (sep != -1)
+ if (sep != -1) {
spec = spec.substring(0, sep);
+ }
return Paths.get(new URI(spec)).toAbsolutePath();
} catch (URISyntaxException e) {
throw new IllegalArgumentException(e.getMessage(), e);
@@ -107,6 +108,9 @@
// assume NOT a zip/jar file
throw new UnsupportedOperationException();
}
+ if (realPath == null) { // newly created
+ realPath = path.toRealPath();
+ }
filesystems.put(realPath, zipfs);
return zipfs;
}
@@ -132,7 +136,6 @@
@Override
public Path getPath(URI uri) {
-
String spec = uri.getSchemeSpecificPart();
int sep = spec.indexOf("!/");
if (sep == -1)
--- a/jdk/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipPath.java Thu Aug 27 13:22:51 2015 -0700
+++ b/jdk/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipPath.java Thu Aug 27 14:32:42 2015 -0700
@@ -32,10 +32,10 @@
import java.nio.file.DirectoryStream.Filter;
import java.nio.file.attribute.*;
import java.util.*;
+import static java.nio.charset.StandardCharsets.UTF_8;
import static java.nio.file.StandardOpenOption.*;
import static java.nio.file.StandardCopyOption.*;
-
/**
*
* @author Xueming Shen, Rajendra Gutupalli,Jaya Hangal
@@ -180,7 +180,7 @@
public URI toUri() {
try {
return new URI("jar",
- zfs.getZipFile().toUri() +
+ decodeUri(zfs.getZipFile().toUri().toString()) +
"!" +
zfs.getString(toAbsolutePath().path),
null);
@@ -866,4 +866,57 @@
}
}
}
+
+ 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;
+ assert false;
+ return -1;
+ }
+
+ // to avoid double escape
+ static String decodeUri(String s) {
+ if (s == null)
+ return s;
+ int n = s.length();
+ if (n == 0)
+ return s;
+ if (s.indexOf('%') < 0)
+ return s;
+
+ StringBuilder sb = new StringBuilder(n);
+ byte[] bb = new byte[n];
+ boolean betweenBrackets = false;
+
+ for (int i = 0; i < n;) {
+ char c = s.charAt(i);
+ if (c == '[') {
+ betweenBrackets = true;
+ } else if (betweenBrackets && c == ']') {
+ betweenBrackets = false;
+ }
+ if (c != '%' || betweenBrackets ) {
+ sb.append(c);
+ i++;
+ continue;
+ }
+ int nb = 0;
+ while (c == '%') {
+ assert (n - i >= 2);
+ bb[nb++] = (byte)(((decode(s.charAt(++i)) & 0xf) << 4) |
+ (decode(s.charAt(++i)) & 0xf));
+ if (++i >= n) {
+ break;
+ }
+ c = s.charAt(i);
+ }
+ sb.append(new String(bb, 0, nb, UTF_8));
+ }
+ return sb.toString();
+ }
+
}
--- a/jdk/test/jdk/nio/zipfs/ZipFSTester.java Thu Aug 27 13:22:51 2015 -0700
+++ b/jdk/test/jdk/nio/zipfs/ZipFSTester.java Thu Aug 27 14:32:42 2015 -0700
@@ -26,6 +26,7 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
+import java.net.URLDecoder;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.SeekableByteChannel;
@@ -69,6 +70,7 @@
* @test
* @bug 6990846 7009092 7009085 7015391 7014948 7005986 7017840 7007596
* 7157656 8002390 7012868 7012856 8015728 8038500 8040059 8069211
+ * 8131067
* @summary Test Zip filesystem provider
* @run main ZipFSTester
* @run main/othervm/java.security.policy=test.policy ZipFSTester
@@ -91,6 +93,7 @@
}
testTime(jarFile);
test8069211();
+ test8131067();
}
static void test0(FileSystem fs)
@@ -441,11 +444,34 @@
}
}
+ static void test8131067() throws Exception {
+ Map<String, Object> env = new HashMap<String, Object>();
+ env.put("create", "true");
+
+ // file name with space character for URI to quote it
+ File tmp = File.createTempFile("test zipfs", "zip");
+ tmp.delete(); // we need a clean path, no file
+ Path fsPath = tmp.toPath();
+ try (FileSystem fs = newZipFileSystem(fsPath, env);) {
+ Files.write(fs.getPath("/foo"), "hello".getBytes());
+ URI fooUri = fs.getPath("/foo").toUri();
+ if (!Arrays.equals(Files.readAllBytes(Paths.get(fooUri)),
+ "hello".getBytes())) {
+ throw new RuntimeException("entry close() failed");
+ }
+ } finally {
+ Files.delete(fsPath);
+ }
+ }
+
private static FileSystem newZipFileSystem(Path path, Map<String, ?> env)
throws Exception
{
+ // Use URLDecoder (for test only) to remove the double escaped space
+ // character
return FileSystems.newFileSystem(
- new URI("jar", path.toUri().toString(), null), env, null);
+ new URI("jar", URLDecoder.decode(path.toUri().toString(), "utf8"),
+ null), env, null);
}
private static Path getTempPath() throws IOException