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

Reply via email to