Skip to content

Commit

Permalink
Improve performance of Tomcat 'jar:war:file' URLs
Browse files Browse the repository at this point in the history
Update jar `Handler` fallback logic to directly support Tomcat
'jar:war:file' URLs. This commit allows contents to be accessed without
the JDK needing to extracted the nested jar to the temporary folder.

Closes gh-24553
  • Loading branch information
philwebb committed Dec 18, 2020
1 parent e0522d9 commit 82791b4
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 2 deletions.
Expand Up @@ -47,6 +47,8 @@ public class Handler extends URLStreamHandler {

private static final String FILE_PROTOCOL = "file:";

private static final String TOMCAT_WARFILE_PROTOCOL = "war:file:";

private static final String SEPARATOR = "!/";

private static final Pattern SEPARATOR_PATTERN = Pattern.compile(SEPARATOR, Pattern.LITERAL);
Expand Down Expand Up @@ -102,7 +104,8 @@ private boolean isUrlInJarFile(URL url, JarFile jarFile) throws MalformedURLExce

private URLConnection openFallbackConnection(URL url, Exception reason) throws IOException {
try {
URLConnection connection = openFallbackContextConnection(url);
URLConnection connection = openFallbackTomcatConnection(url);
connection = (connection != null) ? connection : openFallbackContextConnection(url);
return (connection != null) ? connection : openFallbackHandlerConnection(url);
}
catch (Exception ex) {
Expand All @@ -118,6 +121,44 @@ private URLConnection openFallbackConnection(URL url, Exception reason) throws I
}
}

/**
* Attempt to open a Tomcat formatted 'jar:war:file:...' URL. This method allows us to
* use our own nested JAR support to open the content rather than the logic in
* {@code sun.net.www.protocol.jar.URLJarFile} which will extract the nested jar to
* the temp folder to that its content can be accessed.
* @param url the URL to open
* @return a {@link URLConnection} or {@code null}
*/
private URLConnection openFallbackTomcatConnection(URL url) {
String file = url.getFile();
if (isTomcatWarUrl(file)) {
file = file.substring(TOMCAT_WARFILE_PROTOCOL.length());
file = file.replaceFirst("\\*/", "!/");
try {
URLConnection connection = openConnection(new URL("jar:file:" + file));
connection.getInputStream().close();
return connection;
}
catch (IOException ex) {
}
}
return null;
}

private boolean isTomcatWarUrl(String file) {
if (file.startsWith(TOMCAT_WARFILE_PROTOCOL) || !file.contains("*/")) {
try {
URLConnection connection = new URL(file).openConnection();
if (connection.getClass().getName().startsWith("org.apache.catalina")) {
return true;
}
}
catch (Exception ex) {
}
}
return false;
}

/**
* Attempt to open a fallback connection by using a context URL captured before the
* jar handler was replaced with our own version. Since this method doesn't use
Expand Down
Expand Up @@ -16,6 +16,8 @@

package org.springframework.boot.loaderapp;

import java.io.File;
import java.net.JarURLConnection;
import java.net.URL;
import java.util.Arrays;

Expand All @@ -33,7 +35,14 @@ public class LoaderTestApplication {
@Bean
public CommandLineRunner commandLineRunner(ServletContext servletContext) {
return (args) -> {
File temp = new File(System.getProperty("java.io.tmpdir"));
URL resourceUrl = servletContext.getResource("webjars/jquery/3.5.0/jquery.js");
JarURLConnection connection = (JarURLConnection) resourceUrl.openConnection();
String jarName = connection.getJarFile().getName();
System.out.println(">>>>> jar file " + jarName);
if(jarName.contains(temp.getAbsolutePath())) {
System.out.println(">>>>> jar written to temp");
}
byte[] resourceContent = FileCopyUtils.copyToByteArray(resourceUrl.openStream());
URL directUrl = new URL(resourceUrl.toExternalForm());
byte[] directContent = FileCopyUtils.copyToByteArray(directUrl.openStream());
Expand Down
Expand Up @@ -59,8 +59,9 @@ private static File findApplication() {

@Test
void readUrlsWithoutWarning() {
System.out.println(output.toUtf8String());
assertThat(output.toUtf8String()).contains(">>>>> 287649 BYTES from").doesNotContain("WARNING:")
.doesNotContain("illegal");
.doesNotContain("illegal").doesNotContain("jar written to temp");
}

}

0 comments on commit 82791b4

Please sign in to comment.