Nested ZipFileSystems cause issues with URI parsing
Mitchell Skaggs
skaggsm333 at gmail.com
Sat Jun 6 19:12:51 UTC 2020
Alan,
> The file system API doesn't define a format for so-called compound URIs.
Okay, I just based my fix on the comment describing the syntax as "
jar:{uri}!/{entry}".
> if helps the more general case of N-levels of nesting
I believe it does resolve the issues with more than 1 level of nesting.
> there may be other other in the zipfs provider that will need attention
too
Thanks for reminding me, I included another change in my patch below.
Lance,
> please generate a diff and a concise test
Here's a patch for the fix:
diff --git
a/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystemProvider.java
b/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystemProvider.java
--- a/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystemProvider.java
+++ b/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ZipFileSystemProvider.java
@@ -69,7 +69,7 @@
try {
// only support legacy JAR URL syntax jar:{uri}!/{entry} for
now
String spec = uri.getRawSchemeSpecificPart();
- int sep = spec.indexOf("!/");
+ int sep = spec.lastIndexOf("!/");
if (sep != -1) {
spec = spec.substring(0, sep);
}
@@ -134,7 +134,7 @@
@Override
public Path getPath(URI uri) {
String spec = uri.getSchemeSpecificPart();
- int sep = spec.indexOf("!/");
+ int sep = spec.lastIndexOf("!/");
if (sep == -1)
throw new IllegalArgumentException("URI: "
+ uri
I have a test, but I'm not sure where to put it and how to build everything
on Windows. Here's a "vanilla" version of the test that demonstrates the
issue:
Path zip1Path = Files.createTempFile("zip1", ".zip");
try {
Files.delete(zip1Path);
try (FileSystem zip1 = FileSystems.newFileSystem(zip1Path,
Map.of("create", true))) {
Path zip2Path = zip1.getPath("zip2.zip");
try (FileSystem zip2 = FileSystems.newFileSystem(zip2Path,
Map.of("create", true))) {
Path nestedFilePath = zip2.getPath("test.txt");
Path newPath = Path.of(nestedFilePath.toUri());
assert nestedFilePath.equals(newPath);
}
}
} finally {
try (Stream<Path> walk = Files.walk(zip1Path)) {
walk.sorted(Comparator.reverseOrder())
.forEach(path -> {
try {
Files.delete(path);
} catch (IOException e) {
throw new Error(e);
}
});
}
}
It builds a nested zip file in the system's temp directory, verifies the
path is parsed correctly, and deletes it when finished.
If you need me to build and test everything, I can transfer it to a linux
machine and do it there; it'll just take some time to get a build
environment set up.
Thanks,
Mitchell
On Sat, Jun 6, 2020 at 11:07 AM Alan Bateman <Alan.Bateman at oracle.com>
wrote:
> On 06/06/2020 09:17, Mitchell Skaggs wrote:
>
> Hi everyone,
>
> I ran into a bit of a complex/niche issue, and I'm not surprised it wasn't
> caught or brought up before. I have a situation brought on by Spring's
> Uber-jars where a classpath resource is located inside of two jar files.
> The standard getResourceAsStream, etc. works just fine because of a
> clever implementation of URLStreamHandler that does some zipfile magic to
> find the file offsets inside nested zips. Unfortunately, I need something
> more powerful than an InputStream - I need java.nio.Paths - so I instead
> use getResource and recursively consume that URI, opening/closing
> FileSystems as needed. I expected that to work fine, but due to the way the
> URI is processed by ZipFileSystem, it looks in the wrong place.
>
> The cause of (and fix for) the issue:
>
> After tracing through the code, here's what I believe to be the crux of
> the issue: the ZipFileSystemProvider.getPath(URI) method. That method
> uses String.indexOf on the string representation of the URI. Because of
> the structure of jar-scheme URIs (link
> <https://www.iana.org/assignments/uri-schemes/prov/jar>), it should
> instead use String.lastIndexOf because the first "jar:" scheme is always
> paired with the last "!/" separator. I believe this is a bug, and fixing
> it wouldn't change behavior in situations without nested jar files.
>
> The file system API doesn't define a format for so-called compound URIs.
> You'll find more on this in the Path::toUri javadoc where expectations that
> are set that invoking toUri() on a path to a file in a nested file system
> may not return a URI that encodes the URI of the enclosing file system.
> That said, the URI support for nesting of zip/JAR file systems does work
> for one level of nesting and if helps the more general case of N-levels of
> nesting then we should fix it. In addition to the getPath(URI)
> implementation, there may be other other in the zipfs provider that will
> need attention too. A good set of tests should help shake out any other
> issues.
>
> -Alan.
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.java.net/pipermail/nio-dev/attachments/20200606/0d8619be/attachment-0001.htm>
More information about the nio-dev
mailing list