Skip to content

Commit 048be18

Browse files
committed
Ensure JarFile created for nested entry InputStream is closed
Closes gh-17127
1 parent 29d1cd3 commit 048be18

File tree

1 file changed

+46
-10
lines changed
  • spring-boot-project/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar

1 file changed

+46
-10
lines changed

spring-boot-project/spring-boot-tools/spring-boot-loader/src/main/java/org/springframework/boot/loader/jar/JarURLConnection.java

+46-10
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import java.io.ByteArrayOutputStream;
2020
import java.io.FileNotFoundException;
2121
import java.io.FilePermission;
22+
import java.io.FilterInputStream;
2223
import java.io.IOException;
2324
import java.io.InputStream;
2425
import java.io.UnsupportedEncodingException;
@@ -80,14 +81,18 @@ protected URLConnection openConnection(URL u) throws IOException {
8081

8182
private final JarEntryName jarEntryName;
8283

84+
private final CloseAction closeAction;
85+
8386
private JarEntry jarEntry;
8487

85-
private JarURLConnection(URL url, JarFile jarFile, JarEntryName jarEntryName) throws IOException {
88+
private JarURLConnection(URL url, JarFile jarFile, JarEntryName jarEntryName, CloseAction closeAction)
89+
throws IOException {
8690
// What we pass to super is ultimately ignored
8791
super(EMPTY_JAR_URL);
8892
this.url = url;
8993
this.jarFile = jarFile;
9094
this.jarEntryName = jarEntryName;
95+
this.closeAction = closeAction;
9196
}
9297

9398
@Override
@@ -168,7 +173,17 @@ public InputStream getInputStream() throws IOException {
168173
if (inputStream == null) {
169174
throwFileNotFound(this.jarEntryName, this.jarFile);
170175
}
171-
return inputStream;
176+
return new FilterInputStream(inputStream) {
177+
178+
@Override
179+
public void close() throws IOException {
180+
super.close();
181+
if (JarURLConnection.this.closeAction != null) {
182+
JarURLConnection.this.closeAction.perform();
183+
}
184+
}
185+
186+
};
172187
}
173188

174189
private void throwFileNotFound(Object entry, JarFile jarFile) throws FileNotFoundException {
@@ -249,24 +264,30 @@ static JarURLConnection get(URL url, JarFile jarFile) throws IOException {
249264
int index = indexOfRootSpec(spec, jarFile.getPathFromRoot());
250265
if (index == -1) {
251266
return (Boolean.TRUE.equals(useFastExceptions.get()) ? NOT_FOUND_CONNECTION
252-
: new JarURLConnection(url, null, EMPTY_JAR_ENTRY_NAME));
267+
: new JarURLConnection(url, null, EMPTY_JAR_ENTRY_NAME, null));
253268
}
254269
int separator;
270+
JarFile connectionJarFile = jarFile;
255271
while ((separator = spec.indexOf(SEPARATOR, index)) > 0) {
256272
JarEntryName entryName = JarEntryName.get(spec.subSequence(index, separator));
257273
JarEntry jarEntry = jarFile.getJarEntry(entryName.toCharSequence());
258274
if (jarEntry == null) {
259-
return JarURLConnection.notFound(jarFile, entryName);
275+
return JarURLConnection.notFound(connectionJarFile, entryName,
276+
(connectionJarFile != jarFile) ? connectionJarFile::close : null);
260277
}
261-
jarFile = jarFile.getNestedJarFile(jarEntry);
278+
connectionJarFile = connectionJarFile.getNestedJarFile(jarEntry);
262279
index = separator + SEPARATOR.length();
263280
}
264281
JarEntryName jarEntryName = JarEntryName.get(spec, index);
265282
if (Boolean.TRUE.equals(useFastExceptions.get()) && !jarEntryName.isEmpty()
266-
&& !jarFile.containsEntry(jarEntryName.toString())) {
283+
&& !connectionJarFile.containsEntry(jarEntryName.toString())) {
284+
if (connectionJarFile != jarFile) {
285+
connectionJarFile.close();
286+
}
267287
return NOT_FOUND_CONNECTION;
268288
}
269-
return new JarURLConnection(url, jarFile, jarEntryName);
289+
return new JarURLConnection(url, connectionJarFile, jarEntryName,
290+
(connectionJarFile != jarFile) ? connectionJarFile::close : null);
270291
}
271292

272293
private static int indexOfRootSpec(StringSequence file, String pathFromRoot) {
@@ -279,18 +300,22 @@ private static int indexOfRootSpec(StringSequence file, String pathFromRoot) {
279300

280301
private static JarURLConnection notFound() {
281302
try {
282-
return notFound(null, null);
303+
return notFound(null, null, null);
283304
}
284305
catch (IOException ex) {
285306
throw new IllegalStateException(ex);
286307
}
287308
}
288309

289-
private static JarURLConnection notFound(JarFile jarFile, JarEntryName jarEntryName) throws IOException {
310+
private static JarURLConnection notFound(JarFile jarFile, JarEntryName jarEntryName, CloseAction closeAction)
311+
throws IOException {
290312
if (Boolean.TRUE.equals(useFastExceptions.get())) {
313+
if (closeAction != null) {
314+
closeAction.perform();
315+
}
291316
return NOT_FOUND_CONNECTION;
292317
}
293-
return new JarURLConnection(null, jarFile, jarEntryName);
318+
return new JarURLConnection(null, jarFile, jarEntryName, closeAction);
294319
}
295320

296321
/**
@@ -393,4 +418,15 @@ public static JarEntryName get(StringSequence spec, int beginIndex) {
393418

394419
}
395420

421+
/**
422+
* An action to be taken when the connection is being "closed" and its underlying
423+
* resources are no longer needed.
424+
*/
425+
@FunctionalInterface
426+
private interface CloseAction {
427+
428+
void perform() throws IOException;
429+
430+
}
431+
396432
}

0 commit comments

Comments
 (0)