Author: markt Date: Tue Mar 1 14:20:56 2016 New Revision: 1733077 URL: http://svn.apache.org/viewvc?rev=1733077&view=rev Log: Fix https://bz.apache.org/bugzilla/show_bug.cgi?id=59001 Correctly handle the case when Tomcat is installed on a path where one of the segments ends in an exclamation mark.
Modified: tomcat/trunk/java/org/apache/catalina/startup/ClassLoaderFactory.java tomcat/trunk/java/org/apache/catalina/startup/ContextConfig.java tomcat/trunk/java/org/apache/catalina/startup/HostConfig.java tomcat/trunk/java/org/apache/catalina/startup/Tomcat.java tomcat/trunk/java/org/apache/catalina/webresources/JarResourceSet.java tomcat/trunk/java/org/apache/catalina/webresources/JarWarResourceSet.java tomcat/trunk/java/org/apache/tomcat/util/buf/UriUtil.java tomcat/trunk/java/org/apache/tomcat/util/scan/StandardJarScanner.java tomcat/trunk/webapps/docs/changelog.xml Modified: tomcat/trunk/java/org/apache/catalina/startup/ClassLoaderFactory.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/startup/ClassLoaderFactory.java?rev=1733077&r1=1733076&r2=1733077&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/startup/ClassLoaderFactory.java (original) +++ tomcat/trunk/java/org/apache/catalina/startup/ClassLoaderFactory.java Tue Mar 1 14:20:56 2016 @@ -18,6 +18,7 @@ package org.apache.catalina.startup; import java.io.File; import java.io.IOException; +import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.security.AccessController; @@ -160,7 +161,7 @@ public final class ClassLoaderFactory { if (repositories != null) { for (Repository repository : repositories) { if (repository.getType() == RepositoryType.URL) { - URL url = new URL(repository.getLocation()); + URL url = buildClassLoaderUrl(repository.getLocation()); if (log.isDebugEnabled()) log.debug(" Including URL " + url); set.add(url); @@ -170,7 +171,7 @@ public final class ClassLoaderFactory { if (!validateFile(directory, RepositoryType.DIR)) { continue; } - URL url = directory.toURI().toURL(); + URL url = buildClassLoaderUrl(directory); if (log.isDebugEnabled()) log.debug(" Including directory " + url); set.add(url); @@ -180,7 +181,7 @@ public final class ClassLoaderFactory { if (!validateFile(file, RepositoryType.JAR)) { continue; } - URL url = file.toURI().toURL(); + URL url = buildClassLoaderUrl(file); if (log.isDebugEnabled()) log.debug(" Including jar file " + url); set.add(url); @@ -209,7 +210,7 @@ public final class ClassLoaderFactory { if (log.isDebugEnabled()) log.debug(" Including glob jar file " + file.getAbsolutePath()); - URL url = file.toURI().toURL(); + URL url = buildClassLoaderUrl(file); set.add(url); } } @@ -273,6 +274,30 @@ public final class ClassLoaderFactory { return true; } + + /* + * These two methods would ideally be in the utility class + * org.apache.tomcat.util.buf.UriUtil but that class is not visible until + * after the class loaders have been constructed. + */ + public static URL buildClassLoaderUrl(String urlString) throws MalformedURLException { + // URLs passed to class loaders may point to directories that contain + // JARs. If these URLs are used to construct URLs for resources in a JAR + // the URL will be used as is. It is therefore necessary to ensure that + // the sequence "!/" is not present in a class loader URL. + String result = urlString.replaceAll("!/", "%21/"); + return new URL(result); + } + + + public static URL buildClassLoaderUrl(File file) throws MalformedURLException { + // Could be a directory or a file + String fileUrlString = file.toURI().toURL().toString(); + fileUrlString = fileUrlString.replaceAll("!/", "%21/"); + return new URL(fileUrlString); + } + + public static enum RepositoryType { DIR, GLOB, Modified: tomcat/trunk/java/org/apache/catalina/startup/ContextConfig.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/startup/ContextConfig.java?rev=1733077&r1=1733076&r2=1733077&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/startup/ContextConfig.java (original) +++ tomcat/trunk/java/org/apache/catalina/startup/ContextConfig.java Tue Mar 1 14:20:56 2016 @@ -78,6 +78,7 @@ import org.apache.tomcat.util.bcel.class import org.apache.tomcat.util.bcel.classfile.ElementValue; import org.apache.tomcat.util.bcel.classfile.ElementValuePair; import org.apache.tomcat.util.bcel.classfile.JavaClass; +import org.apache.tomcat.util.buf.UriUtil; import org.apache.tomcat.util.descriptor.XmlErrorHandler; import org.apache.tomcat.util.descriptor.web.ContextEjb; import org.apache.tomcat.util.descriptor.web.ContextEnvironment; @@ -608,7 +609,7 @@ public class ContextConfig implements Li boolean docBaseInAppBase = docBase.startsWith(appBase.getPath() + File.separatorChar); if (docBase.toLowerCase(Locale.ENGLISH).endsWith(".war") && !file.isDirectory()) { - URL war = new URL("jar:" + (new File(docBase)).toURI().toURL() + "!/"); + URL war = UriUtil.buildJarUrl(new File(docBase)); if (unpackWARs) { docBase = ExpandWar.expand(host, war, pathName); file = new File(docBase); @@ -624,7 +625,7 @@ public class ContextConfig implements Li File warFile = new File(docBase + ".war"); URL war = null; if (warFile.exists() && docBaseInAppBase) { - war = new URL("jar:" + warFile.toURI().toURL() + "!/"); + war = UriUtil.buildJarUrl(warFile); } if (docDir.exists()) { if (war != null && unpackWARs) { Modified: tomcat/trunk/java/org/apache/catalina/startup/HostConfig.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/startup/HostConfig.java?rev=1733077&r1=1733076&r2=1733077&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/startup/HostConfig.java (original) +++ tomcat/trunk/java/org/apache/catalina/startup/HostConfig.java Tue Mar 1 14:20:56 2016 @@ -22,7 +22,6 @@ import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; -import java.net.URL; import java.nio.file.Files; import java.util.ArrayList; import java.util.HashMap; @@ -59,6 +58,7 @@ import org.apache.catalina.util.ContextN import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.ExceptionUtils; +import org.apache.tomcat.util.buf.UriUtil; import org.apache.tomcat.util.digester.Digester; import org.apache.tomcat.util.modeler.Registry; import org.apache.tomcat.util.res.StringManager; @@ -852,9 +852,8 @@ public class HostConfig implements Lifec if (context == null) { context = new FailedContext(); } - context.setConfigFile(new URL("jar:" + - war.toURI().toString() + "!/" + - Constants.ApplicationContextXml)); + context.setConfigFile( + UriUtil.buildJarUrl(war, Constants.ApplicationContextXml)); } } } else if (!deployXML && xmlInWar) { Modified: tomcat/trunk/java/org/apache/catalina/startup/Tomcat.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/startup/Tomcat.java?rev=1733077&r1=1733076&r2=1733077&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/startup/Tomcat.java (original) +++ tomcat/trunk/java/org/apache/catalina/startup/Tomcat.java Tue Mar 1 14:20:56 2016 @@ -61,6 +61,7 @@ import org.apache.catalina.core.Standard import org.apache.catalina.core.StandardWrapper; import org.apache.catalina.realm.GenericPrincipal; import org.apache.catalina.realm.RealmBase; +import org.apache.tomcat.util.buf.UriUtil; import org.apache.tomcat.util.descriptor.web.LoginConfig; // TODO: lazy init for the temp dir - only when a JSP is compiled or @@ -1203,8 +1204,7 @@ public class Tomcat { try (JarFile jar = new JarFile(docBase)) { JarEntry entry = jar.getJarEntry(Constants.ApplicationContextXml); if (entry != null) { - result = new URL("jar:" + docBase.toURI().toString() + "!/" - + Constants.ApplicationContextXml); + result = UriUtil.buildJarUrl(docBase, Constants.ApplicationContextXml); } } catch (IOException e) { Logger.getLogger(getLoggerName(getHost(), contextName)).log(Level.WARNING, Modified: tomcat/trunk/java/org/apache/catalina/webresources/JarResourceSet.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/webresources/JarResourceSet.java?rev=1733077&r1=1733076&r2=1733077&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/webresources/JarResourceSet.java (original) +++ tomcat/trunk/java/org/apache/catalina/webresources/JarResourceSet.java Tue Mar 1 14:20:56 2016 @@ -28,6 +28,7 @@ import java.util.jar.Manifest; import org.apache.catalina.LifecycleException; import org.apache.catalina.WebResource; import org.apache.catalina.WebResourceRoot; +import org.apache.tomcat.util.buf.UriUtil; /** * Represents a {@link org.apache.catalina.WebResourceSet} based on a JAR file. @@ -139,7 +140,7 @@ public class JarResourceSet extends Abst } try { - setBaseUrl((new File(getBase())).toURI().toURL()); + setBaseUrl(UriUtil.buildJarSafeUrl(new File(getBase()))); } catch (MalformedURLException e) { throw new IllegalArgumentException(e); } Modified: tomcat/trunk/java/org/apache/catalina/webresources/JarWarResourceSet.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/webresources/JarWarResourceSet.java?rev=1733077&r1=1733076&r2=1733077&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/webresources/JarWarResourceSet.java (original) +++ tomcat/trunk/java/org/apache/catalina/webresources/JarWarResourceSet.java Tue Mar 1 14:20:56 2016 @@ -29,6 +29,7 @@ import java.util.jar.Manifest; import org.apache.catalina.LifecycleException; import org.apache.catalina.WebResource; import org.apache.catalina.WebResourceRoot; +import org.apache.tomcat.util.buf.UriUtil; /** * Represents a {@link org.apache.catalina.WebResourceSet} based on a JAR file @@ -162,7 +163,7 @@ public class JarWarResourceSet extends A } try { - setBaseUrl((new File(getBase())).toURI().toURL()); + setBaseUrl(UriUtil.buildJarSafeUrl(new File(getBase()))); } catch (MalformedURLException e) { throw new IllegalArgumentException(e); } Modified: tomcat/trunk/java/org/apache/tomcat/util/buf/UriUtil.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/buf/UriUtil.java?rev=1733077&r1=1733076&r2=1733077&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/util/buf/UriUtil.java (original) +++ tomcat/trunk/java/org/apache/tomcat/util/buf/UriUtil.java Tue Mar 1 14:20:56 2016 @@ -16,6 +16,10 @@ */ package org.apache.tomcat.util.buf; +import java.io.File; +import java.net.MalformedURLException; +import java.net.URL; + /** * Utility class for working with URIs and URLs. */ @@ -59,4 +63,49 @@ public final class UriUtil { } return false; } + + + public static URL buildJarUrl(File jarFile) throws MalformedURLException { + return buildJarUrl(jarFile, null); + } + + + public static URL buildJarUrl(File jarFile, String entryPath) throws MalformedURLException { + return buildJarUrl(jarFile.toURI().toURL().toString(), entryPath); + } + + + public static URL buildJarUrl(String fileUrlString) throws MalformedURLException { + return buildJarUrl(fileUrlString, null); + } + + + public static URL buildJarUrl(String fileUrlString, String entryPath) throws MalformedURLException { + String safeString = makeSafeForJarUrl(fileUrlString); + StringBuilder sb = new StringBuilder(); + sb.append("jar:"); + sb.append(safeString); + sb.append("!/"); + if (entryPath != null) { + sb.append(makeSafeForJarUrl(entryPath)); + } + return new URL(sb.toString()); + } + + + public static URL buildJarSafeUrl(File file) throws MalformedURLException { + String safe = makeSafeForJarUrl(file.toURI().toURL().toString()); + return new URL(safe); + } + + + /* + * Pulled out into a separate method in case we need to handle other unusual + * sequences in the future. + */ + private static String makeSafeForJarUrl(String input) { + // Since "!/" has a special meaning in a JAR URL, make sure that the + // sequence is properly escaped if present. + return input.replaceAll("!/", "%21/"); + } } Modified: tomcat/trunk/java/org/apache/tomcat/util/scan/StandardJarScanner.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/scan/StandardJarScanner.java?rev=1733077&r1=1733076&r2=1733077&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/util/scan/StandardJarScanner.java (original) +++ tomcat/trunk/java/org/apache/tomcat/util/scan/StandardJarScanner.java Tue Mar 1 14:20:56 2016 @@ -36,6 +36,7 @@ import org.apache.tomcat.JarScanType; import org.apache.tomcat.JarScanner; import org.apache.tomcat.JarScannerCallback; import org.apache.tomcat.util.ExceptionUtils; +import org.apache.tomcat.util.buf.UriUtil; import org.apache.tomcat.util.res.StringManager; /** @@ -317,7 +318,7 @@ public class StandardJarScanner implemen String urlStr = url.toString(); if (urlStr.startsWith("file:") || urlStr.startsWith("http:") || urlStr.startsWith("https:")) { if (urlStr.endsWith(Constants.JAR_EXT)) { - URL jarURL = new URL("jar:" + urlStr + "!/"); + URL jarURL = UriUtil.buildJarUrl(urlStr); callback.scan((JarURLConnection) jarURL.openConnection(), webappPath, isWebapp); } else { @@ -326,7 +327,7 @@ public class StandardJarScanner implemen f = new File(url.toURI()); if (f.isFile() && isScanAllFiles()) { // Treat this file as a JAR - URL jarURL = new URL("jar:" + urlStr + "!/"); + URL jarURL = UriUtil.buildJarUrl(f); callback.scan( (JarURLConnection) jarURL.openConnection(), webappPath, isWebapp); Modified: tomcat/trunk/webapps/docs/changelog.xml URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/changelog.xml?rev=1733077&r1=1733076&r2=1733077&view=diff ============================================================================== --- tomcat/trunk/webapps/docs/changelog.xml (original) +++ tomcat/trunk/webapps/docs/changelog.xml Tue Mar 1 14:20:56 2016 @@ -103,6 +103,10 @@ modified Context configuration parameters and reduces (slightly) the memory footprint of a running Tomcat instance. (markt) </fix> + <fix> + <bug>59001</bug>: Correctly handle the case when Tomcat is installed on + a path where one of the segments ends in an exclamation mark. (markt) + </fix> <update> Switch to the web application class loader to the <code>ParallelWebappClassLoader</code> by default. (markt) --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org