Ensure that StaticResourceJars does not close cached jars
Update `StaticResourceJars` so that jars obtained via a `JarURLConnection` are only closed when caches are not being used. Fixes gh-38766
This commit is contained in:
		
							parent
							
								
									82bc9a6280
								
							
						
					
					
						commit
						da31137596
					
				|  | @ -115,7 +115,7 @@ class StaticResourceJars { | ||||||
| 
 | 
 | ||||||
| 	private boolean isResourcesJar(JarURLConnection connection) { | 	private boolean isResourcesJar(JarURLConnection connection) { | ||||||
| 		try { | 		try { | ||||||
| 			return isResourcesJar(connection.getJarFile()); | 			return isResourcesJar(connection.getJarFile(), !connection.getUseCaches()); | ||||||
| 		} | 		} | ||||||
| 		catch (IOException ex) { | 		catch (IOException ex) { | ||||||
| 			return false; | 			return false; | ||||||
|  | @ -124,16 +124,21 @@ class StaticResourceJars { | ||||||
| 
 | 
 | ||||||
| 	private boolean isResourcesJar(File file) { | 	private boolean isResourcesJar(File file) { | ||||||
| 		try { | 		try { | ||||||
| 			return isResourcesJar(new JarFile(file)); | 			return isResourcesJar(new JarFile(file), true); | ||||||
| 		} | 		} | ||||||
| 		catch (IOException | InvalidPathException ex) { | 		catch (IOException | InvalidPathException ex) { | ||||||
| 			return false; | 			return false; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	private boolean isResourcesJar(JarFile jar) throws IOException { | 	private boolean isResourcesJar(JarFile jarFile, boolean closeJarFile) throws IOException { | ||||||
| 		try (jar) { | 		try { | ||||||
| 			return jar.getName().endsWith(".jar") && (jar.getJarEntry("META-INF/resources") != null); | 			return jarFile.getName().endsWith(".jar") && (jarFile.getJarEntry("META-INF/resources") != null); | ||||||
|  | 		} | ||||||
|  | 		finally { | ||||||
|  | 			if (closeJarFile) { | ||||||
|  | 				jarFile.close(); | ||||||
|  | 			} | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -19,7 +19,10 @@ package org.springframework.boot.web.servlet.server; | ||||||
| import java.io.File; | import java.io.File; | ||||||
| import java.io.FileOutputStream; | import java.io.FileOutputStream; | ||||||
| import java.io.IOException; | import java.io.IOException; | ||||||
|  | import java.net.JarURLConnection; | ||||||
| import java.net.URL; | import java.net.URL; | ||||||
|  | import java.net.URLConnection; | ||||||
|  | import java.net.URLStreamHandler; | ||||||
| import java.util.List; | import java.util.List; | ||||||
| import java.util.function.Consumer; | import java.util.function.Consumer; | ||||||
| import java.util.jar.JarEntry; | import java.util.jar.JarEntry; | ||||||
|  | @ -29,6 +32,8 @@ import org.junit.jupiter.api.Test; | ||||||
| import org.junit.jupiter.api.io.TempDir; | import org.junit.jupiter.api.io.TempDir; | ||||||
| 
 | 
 | ||||||
| import static org.assertj.core.api.Assertions.assertThat; | import static org.assertj.core.api.Assertions.assertThat; | ||||||
|  | import static org.assertj.core.api.Assertions.assertThatIllegalStateException; | ||||||
|  | import static org.assertj.core.api.Assertions.assertThatNoException; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * Tests for {@link StaticResourceJars}. |  * Tests for {@link StaticResourceJars}. | ||||||
|  | @ -86,6 +91,27 @@ class StaticResourceJarsTests { | ||||||
| 		assertThat(staticResourceJarUrls).isEmpty(); | 		assertThat(staticResourceJarUrls).isEmpty(); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	@Test | ||||||
|  | 	void doesNotCloseJarFromCachedConnection() throws Exception { | ||||||
|  | 		File jarFile = createResourcesJar("test-resources.jar"); | ||||||
|  | 		TrackedURLStreamHandler handler = new TrackedURLStreamHandler(true); | ||||||
|  | 		URL url = new URL("jar", null, 0, jarFile.toURI().toURL().toString() + "!/", handler); | ||||||
|  | 		new StaticResourceJars().getUrlsFrom(url); | ||||||
|  | 		assertThatNoException() | ||||||
|  | 			.isThrownBy(() -> ((JarURLConnection) handler.getConnection()).getJarFile().getComment()); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	@Test | ||||||
|  | 	void closesJarFromNonCachedConnection() throws Exception { | ||||||
|  | 		File jarFile = createResourcesJar("test-resources.jar"); | ||||||
|  | 		TrackedURLStreamHandler handler = new TrackedURLStreamHandler(false); | ||||||
|  | 		URL url = new URL("jar", null, 0, jarFile.toURI().toURL().toString() + "!/", handler); | ||||||
|  | 		new StaticResourceJars().getUrlsFrom(url); | ||||||
|  | 		assertThatIllegalStateException() | ||||||
|  | 			.isThrownBy(() -> ((JarURLConnection) handler.getConnection()).getJarFile().getComment()) | ||||||
|  | 			.withMessageContaining("closed"); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	private File createResourcesJar(String name) throws IOException { | 	private File createResourcesJar(String name) throws IOException { | ||||||
| 		return createJar(name, (output) -> { | 		return createJar(name, (output) -> { | ||||||
| 			JarEntry jarEntry = new JarEntry("META-INF/resources"); | 			JarEntry jarEntry = new JarEntry("META-INF/resources"); | ||||||
|  | @ -113,4 +139,27 @@ class StaticResourceJarsTests { | ||||||
| 		return jarFile; | 		return jarFile; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	private static class TrackedURLStreamHandler extends URLStreamHandler { | ||||||
|  | 
 | ||||||
|  | 		private final boolean useCaches; | ||||||
|  | 
 | ||||||
|  | 		private URLConnection connection; | ||||||
|  | 
 | ||||||
|  | 		TrackedURLStreamHandler(boolean useCaches) { | ||||||
|  | 			this.useCaches = useCaches; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		@Override | ||||||
|  | 		protected URLConnection openConnection(URL u) throws IOException { | ||||||
|  | 			this.connection = new URL(u.toExternalForm()).openConnection(); | ||||||
|  | 			this.connection.setUseCaches(this.useCaches); | ||||||
|  | 			return this.connection; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		URLConnection getConnection() { | ||||||
|  | 			return this.connection; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue