You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by ma...@apache.org on 2023/02/27 17:02:11 UTC

[tomcat] branch main updated (87294850f5 -> 0dda748db2)

This is an automated email from the ASF dual-hosted git repository.

markt pushed a change to branch main
in repository https://gitbox.apache.org/repos/asf/tomcat.git


    from 87294850f5 Merge branch 'main' of https://gitbox.apache.org/repos/asf/tomcat
     new 6e83c093f2 Revert "Refactcor custom URL handler to use ServiceLoader"
     new 2d90b7a9f5 Revert incorrect BZ 66491 fix
     new 0dda748db2 Follow up to reverting custom URL handler for war

The 3 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 bin/catalina.bat                                   |   3 +
 bin/catalina.sh                                    |   3 +
 build.xml                                          |   5 +-
 .../catalina/loader/WebappClassLoaderBase.java     |   4 +
 .../apache/catalina/webresources/StandardRoot.java |  11 +-
 .../TomcatURLStreamHandlerFactory.java             | 164 +++++++++++++++++++++
 .../services/java.net.spi.URLStreamHandlerProvider |  16 --
 .../services/java.net.spi.URLStreamHandlerProvider |  16 --
 res/bnd/catalina.jar.tmp.bnd                       |   2 -
 res/bnd/tomcat-embed-core.jar.tmp.bnd              |   2 -
 .../services/java.net.spi.URLStreamHandlerProvider |  17 ---
 .../TestClasspathUrlStreamHandler.java             |   6 +
 .../webresources/TestJarWarResourceSet.java        |   7 +
 .../TestTomcatURLStreamHandlerFactory.java         |  35 +++--
 .../catalina/webresources/war/TestHandler.java     |   9 ++
 .../webresources/war/TestWarURLConnection.java     |   9 ++
 .../apache/tomcat/util/buf/TesterUriUtilBase.java  |   3 +
 .../tomcat/util/file/TestConfigFileLoader.java     |   2 +
 .../util/scan/TestAbstractInputStreamJar.java      |   8 +
 webapps/docs/changelog.xml                         |   6 +-
 20 files changed, 247 insertions(+), 81 deletions(-)
 create mode 100644 java/org/apache/catalina/webresources/TomcatURLStreamHandlerFactory.java
 delete mode 100644 res/META-INF/catalina.jar/services/java.net.spi.URLStreamHandlerProvider
 delete mode 100644 res/META-INF/tomcat-embed-core.jar/services/java.net.spi.URLStreamHandlerProvider
 delete mode 100644 test/META-INF/services/java.net.spi.URLStreamHandlerProvider
 rename java/org/apache/catalina/webresources/TomcatURLStreamHandlerProvider.java => test/org/apache/catalina/webresources/TestTomcatURLStreamHandlerFactory.java (56%)


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[tomcat] 03/03: Follow up to reverting custom URL handler for war

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

markt pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit 0dda748db209a2e8eefd6d19bef22d8ec09ab346
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Mon Feb 27 16:44:01 2023 +0000

    Follow up to reverting custom URL handler for war
    
    Reviewed 9.0.x / 10.0.x / 11.0.x diff and aligned code
---
 build.xml                                          |  3 +-
 .../TomcatURLStreamHandlerFactory.java             | 44 ++++++++--------------
 2 files changed, 17 insertions(+), 30 deletions(-)

diff --git a/build.xml b/build.xml
index 9070c52281..123b6002ce 100644
--- a/build.xml
+++ b/build.xml
@@ -103,7 +103,7 @@
   <!-- build output directory for generated reflectionless code -->
   <property name="tomcat.xreflect"       value="${tomcat.output}/xreflect"/>
 
-  <!-- Jakarta EE 10 platform requires Java 11+ -->
+  <!-- Jakarta EE 11 platform requires Java 21+ -->
   <!-- Keep in sync with webapps/docs/tomcat-docs.xsl -->
   <property name="compile.release" value="17"/>
   <property name="min.java.version" value="17"/>
@@ -297,7 +297,6 @@
     <include name="**/jakarta.servlet.ServletContainerInitializer"/>
     <include name="**/jakarta.websocket.ContainerProvider"/>
     <include name="**/jakarta.websocket.server.ServerEndpointConfig$Configurator"/>
-    <include name="**/java.net.spi.URLStreamHandlerProvider"/>
     <include name="**/.gitignore"/>
     <include name="**/*.bnd"/>
     <include name="**/*.classpath"/>
diff --git a/java/org/apache/catalina/webresources/TomcatURLStreamHandlerFactory.java b/java/org/apache/catalina/webresources/TomcatURLStreamHandlerFactory.java
index d58f9d3fef..02a0842eea 100644
--- a/java/org/apache/catalina/webresources/TomcatURLStreamHandlerFactory.java
+++ b/java/org/apache/catalina/webresources/TomcatURLStreamHandlerFactory.java
@@ -33,9 +33,8 @@ public class TomcatURLStreamHandlerFactory implements URLStreamHandlerFactory {
     private static volatile TomcatURLStreamHandlerFactory instance = null;
 
     /**
-     * Obtain a reference to the singleton instance. It is recommended that
-     * callers check the value of {@link #isRegistered()} before using the
-     * returned instance.
+     * Obtain a reference to the singleton instance. It is recommended that callers check the value of
+     * {@link #isRegistered()} before using the returned instance.
      *
      * @return A reference to the singleton instance
      */
@@ -61,17 +60,14 @@ public class TomcatURLStreamHandlerFactory implements URLStreamHandlerFactory {
     private final boolean registered;
 
     // List of factories for application defined stream handler factories.
-    private final List<URLStreamHandlerFactory> userFactories =
-            new CopyOnWriteArrayList<>();
+    private final List<URLStreamHandlerFactory> userFactories = new CopyOnWriteArrayList<>();
 
     /**
-     * Register this factory with the JVM. May be called more than once. The
-     * implementation ensures that registration only occurs once.
+     * Register this factory with the JVM. May be called more than once. The implementation ensures that registration
+     * only occurs once.
      *
-     * @return <code>true</code> if the factory is already registered with the
-     *         JVM or was successfully registered as a result of this call.
-     *         <code>false</code> if the factory was disabled prior to this
-     *         call.
+     * @return <code>true</code> if the factory is already registered with the JVM or was successfully registered as a
+     *             result of this call. <code>false</code> if the factory was disabled prior to this call.
      */
     public static boolean register() {
         return getInstanceInternal(true).isRegistered();
@@ -79,13 +75,10 @@ public class TomcatURLStreamHandlerFactory implements URLStreamHandlerFactory {
 
 
     /**
-     * Prevent this this factory from registering with the JVM. May be called
-     * more than once.
+     * Prevent this this factory from registering with the JVM. May be called more than once.
      *
-     * @return <code>true</code> if the factory is already disabled or was
-     *         successfully disabled as a result of this call.
-     *         <code>false</code> if the factory was already registered prior
-     *         to this call.
+     * @return <code>true</code> if the factory is already disabled or was successfully disabled as a result of this
+     *             call. <code>false</code> if the factory was already registered prior to this call.
      */
     public static boolean disable() {
         return !getInstanceInternal(false).isRegistered();
@@ -93,9 +86,8 @@ public class TomcatURLStreamHandlerFactory implements URLStreamHandlerFactory {
 
 
     /**
-     * Release references to any user provided factories that have been loaded
-     * using the provided class loader. Called during web application stop to
-     * prevent memory leaks.
+     * Release references to any user provided factories that have been loaded using the provided class loader. Called
+     * during web application stop to prevent memory leaks.
      *
      * @param classLoader The class loader to release
      */
@@ -137,13 +129,10 @@ public class TomcatURLStreamHandlerFactory implements URLStreamHandlerFactory {
 
 
     /**
-     * Since the JVM only allows a single call to
-     * {@link URL#setURLStreamHandlerFactory(URLStreamHandlerFactory)} and
-     * Tomcat needs to register a handler, provide a mechanism to allow
-     * applications to register their own handlers.
+     * Since the JVM only allows a single call to {@link URL#setURLStreamHandlerFactory(URLStreamHandlerFactory)} and
+     * Tomcat needs to register a handler, provide a mechanism to allow applications to register their own handlers.
      *
-     * @param factory The user provided factory to add to the factories Tomcat
-     *                has already registered
+     * @param factory The user provided factory to add to the factories Tomcat has already registered
      */
     public void addUserFactory(URLStreamHandlerFactory factory) {
         userFactories.add(factory);
@@ -163,8 +152,7 @@ public class TomcatURLStreamHandlerFactory implements URLStreamHandlerFactory {
 
         // Application handlers
         for (URLStreamHandlerFactory factory : userFactories) {
-            URLStreamHandler handler =
-                factory.createURLStreamHandler(protocol);
+            URLStreamHandler handler = factory.createURLStreamHandler(protocol);
             if (handler != null) {
                 return handler;
             }


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[tomcat] 02/03: Revert incorrect BZ 66491 fix

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

markt pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit 2d90b7a9f598872ee0b82805ad0be50efd40c16a
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Mon Feb 27 16:08:38 2023 +0000

    Revert incorrect BZ 66491 fix
    
    Revert parts of 57f5075a00d3c243d3ebe888f09b8b11b1fbc416
    https://bz.apache.org/bugzilla/show_bug.cgi?id=66491
---
 res/bnd/catalina.jar.tmp.bnd          |  2 --
 res/bnd/tomcat-embed-core.jar.tmp.bnd |  2 --
 webapps/docs/changelog.xml            | 11 +++--------
 3 files changed, 3 insertions(+), 12 deletions(-)

diff --git a/res/bnd/catalina.jar.tmp.bnd b/res/bnd/catalina.jar.tmp.bnd
index b8a0814a6c..7579a233b1 100644
--- a/res/bnd/catalina.jar.tmp.bnd
+++ b/res/bnd/catalina.jar.tmp.bnd
@@ -46,8 +46,6 @@ Export-Package: \
     org.apache.catalina.manager.util,\
     org.apache.catalina
 
--includeresource.meta-inf: /META-INF/=${tomcat.output}/manifests/catalina.jar/
-
 -jpms-module-info: \
     ${module.name};\
         access=32;\
diff --git a/res/bnd/tomcat-embed-core.jar.tmp.bnd b/res/bnd/tomcat-embed-core.jar.tmp.bnd
index e85c0b5204..2c0f8e7495 100644
--- a/res/bnd/tomcat-embed-core.jar.tmp.bnd
+++ b/res/bnd/tomcat-embed-core.jar.tmp.bnd
@@ -123,8 +123,6 @@ Provide-Capability: \
         Implementation-Version=${servlet.spec.version}${servlet.revision};\
         Implementation-Vendor=Apache Software Foundation
 
--includeresource.meta-inf: /META-INF/=${tomcat.output}/manifests/tomcat-embed-core.jar/
-
 -jpms-module-info: \
     ${module.name};\
         access=32;\
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index feaabd8985..06e690ea4a 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -125,15 +125,10 @@
         an HTTP request using the CONNECT method. (markt)
       </update>
       <fix>
-        <bug>66491</bug>: Correct the BND configuration used by the build script
-        so that the provider configuration file required by Tomcat's custom URL
-        protocol for WAR files is retained when adding OSGi meta-data. (markt)
+        <bug>66491</bug>: Revert the switch to using the ServiceLoader mechanism
+        to load the custom URL protocol handlers that Tomcat uses. The original
+        system property based approach has been restored. (markt)
       </fix>
-      <update>
-        Revert switch to using the ServiceLoader mechanism to load the custom URL
-        protocol handlers that Tomcat uses. The original system property based
-        approach has been restored. (markt)
-      </update>
     </changelog>
   </subsection>
   <subsection name="Coyote">


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org


[tomcat] 01/03: Revert "Refactcor custom URL handler to use ServiceLoader"

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

markt pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit 6e83c093f2b674dfcdb06151392d0651a8b880ff
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Mon Feb 27 16:01:22 2023 +0000

    Revert "Refactcor custom URL handler to use ServiceLoader"
    
    This reverts commits:
      4c70a12e8aac4081a11f200a7e70f0db30a6c79b.
      3a2db66ffd4efb9f9d8f5c7b916477f62f32441c.
      6b4d6ba0fad9f233e492618ea0bbcbaa307605fc.
      f949ac1cd08004d1a149d3a411b079c7712e44bb.
      0782f0b919b5131a9423c91333f7c557954336a3.
---
 bin/catalina.bat                                   |   3 +
 bin/catalina.sh                                    |   3 +
 build.xml                                          |   2 -
 .../catalina/loader/WebappClassLoaderBase.java     |   4 +
 .../apache/catalina/webresources/StandardRoot.java |  11 +-
 .../TomcatURLStreamHandlerFactory.java             | 176 +++++++++++++++++++++
 .../services/java.net.spi.URLStreamHandlerProvider |  16 --
 .../services/java.net.spi.URLStreamHandlerProvider |  16 --
 .../services/java.net.spi.URLStreamHandlerProvider |  17 --
 .../TestClasspathUrlStreamHandler.java             |   6 +
 .../webresources/TestJarWarResourceSet.java        |   7 +
 .../TestTomcatURLStreamHandlerFactory.java         |  35 ++--
 .../catalina/webresources/war/TestHandler.java     |   9 ++
 .../webresources/war/TestWarURLConnection.java     |   9 ++
 .../apache/tomcat/util/buf/TesterUriUtilBase.java  |   3 +
 .../tomcat/util/file/TestConfigFileLoader.java     |   2 +
 .../util/scan/TestAbstractInputStreamJar.java      |   8 +
 webapps/docs/changelog.xml                         |   5 +
 18 files changed, 260 insertions(+), 72 deletions(-)

diff --git a/bin/catalina.bat b/bin/catalina.bat
index 068cd283bc..ce73b88044 100755
--- a/bin/catalina.bat
+++ b/bin/catalina.bat
@@ -203,6 +203,9 @@ set "JSSE_OPTS=-Djdk.tls.ephemeralDHKeySize=2048"
 :gotJsseOpts
 set "JAVA_OPTS=%JAVA_OPTS% %JSSE_OPTS%"
 
+rem Register custom URL handlers
+set "JAVA_OPTS=%JAVA_OPTS% -Djava.protocol.handler.pkgs=org.apache.catalina.webresources"
+
 if not "%CATALINA_LOGGING_CONFIG%" == "" goto noJuliConfig
 set CATALINA_LOGGING_CONFIG=-Dnop
 if not exist "%CATALINA_BASE%\conf\logging.properties" goto noJuliConfig
diff --git a/bin/catalina.sh b/bin/catalina.sh
index a7b14b6957..d987738b27 100755
--- a/bin/catalina.sh
+++ b/bin/catalina.sh
@@ -251,6 +251,9 @@ if [ -z "$JSSE_OPTS" ] ; then
 fi
 JAVA_OPTS="$JAVA_OPTS $JSSE_OPTS"
 
+# Register custom URL handlers
+JAVA_OPTS="$JAVA_OPTS -Djava.protocol.handler.pkgs=org.apache.catalina.webresources"
+
 # Set juli LogManager config file if it is present and an override has not been issued
 if [ -z "$CATALINA_LOGGING_CONFIG" ]; then
   if [ -r "$CATALINA_BASE"/conf/logging.properties ]; then
diff --git a/build.xml b/build.xml
index d51f3045cf..9070c52281 100644
--- a/build.xml
+++ b/build.xml
@@ -1169,7 +1169,6 @@
     <jarIt jarfile="${catalina.jar}"
       filesDir="${tomcat.classes}"
       filesId="files.catalina"
-      meta-inf="${tomcat.manifests}/catalina.jar"
       addOSGi="true" />
 
     <!-- Catalina Cluster/HA JAR File -->
@@ -1699,7 +1698,6 @@
            filesId="files.tomcat-embed-core"
            notice="${tomcat.manifests}/servlet-api.jar.notice"
            license="${tomcat.manifests}/servlet-api.jar.license"
-           meta-inf="${tomcat.manifests}/tomcat-embed-core.jar"
            addOSGi="true"
            addGraal="true"
            graalPrefix="org.apache.tomcat.embed/tomcat-embed-core"
diff --git a/java/org/apache/catalina/loader/WebappClassLoaderBase.java b/java/org/apache/catalina/loader/WebappClassLoaderBase.java
index 2addcb83c8..b637fdd323 100644
--- a/java/org/apache/catalina/loader/WebappClassLoaderBase.java
+++ b/java/org/apache/catalina/loader/WebappClassLoaderBase.java
@@ -61,6 +61,7 @@ import org.apache.catalina.LifecycleListener;
 import org.apache.catalina.LifecycleState;
 import org.apache.catalina.WebResource;
 import org.apache.catalina.WebResourceRoot;
+import org.apache.catalina.webresources.TomcatURLStreamHandlerFactory;
 import org.apache.juli.WebappProperties;
 import org.apache.juli.logging.Log;
 import org.apache.juli.logging.LogFactory;
@@ -1542,6 +1543,9 @@ public abstract class WebappClassLoaderBase extends URLClassLoader
 
         // Clear the classloader reference in the VM's bean introspector
         java.beans.Introspector.flushCaches();
+
+        // Clear any custom URLStreamHandlers
+        TomcatURLStreamHandlerFactory.release(this);
     }
 
 
diff --git a/java/org/apache/catalina/webresources/StandardRoot.java b/java/org/apache/catalina/webresources/StandardRoot.java
index 3609e2c368..2cb98e277a 100644
--- a/java/org/apache/catalina/webresources/StandardRoot.java
+++ b/java/org/apache/catalina/webresources/StandardRoot.java
@@ -45,6 +45,7 @@ import org.apache.catalina.util.LifecycleMBeanBase;
 import org.apache.juli.logging.Log;
 import org.apache.juli.logging.LogFactory;
 import org.apache.tomcat.util.buf.UriUtil;
+import org.apache.tomcat.util.compat.JreCompat;
 import org.apache.tomcat.util.http.RequestUtil;
 import org.apache.tomcat.util.res.StringManager;
 
@@ -691,12 +692,12 @@ public class StandardRoot extends LifecycleMBeanBase implements WebResourceRoot
         }
     }
 
-    /**
-     * @deprecated Unused. Will be removed in Tomcat 11 onwards.
-     */
-    @Deprecated
     protected void registerURLStreamHandlerFactory() {
-        // NO-OP
+        if (!JreCompat.isGraalAvailable()) {
+            // Ensure support for jar:war:file:/ URLs will be available (required
+            // for resource JARs in packed WAR files).
+            TomcatURLStreamHandlerFactory.register();
+        }
     }
 
     @Override
diff --git a/java/org/apache/catalina/webresources/TomcatURLStreamHandlerFactory.java b/java/org/apache/catalina/webresources/TomcatURLStreamHandlerFactory.java
new file mode 100644
index 0000000000..d58f9d3fef
--- /dev/null
+++ b/java/org/apache/catalina/webresources/TomcatURLStreamHandlerFactory.java
@@ -0,0 +1,176 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.catalina.webresources;
+
+import java.net.URL;
+import java.net.URLStreamHandler;
+import java.net.URLStreamHandlerFactory;
+import java.util.List;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import org.apache.catalina.webresources.war.Handler;
+
+public class TomcatURLStreamHandlerFactory implements URLStreamHandlerFactory {
+
+    private static final String WAR_PROTOCOL = "war";
+    private static final String CLASSPATH_PROTOCOL = "classpath";
+
+    // Singleton instance
+    private static volatile TomcatURLStreamHandlerFactory instance = null;
+
+    /**
+     * Obtain a reference to the singleton instance. It is recommended that
+     * callers check the value of {@link #isRegistered()} before using the
+     * returned instance.
+     *
+     * @return A reference to the singleton instance
+     */
+    public static TomcatURLStreamHandlerFactory getInstance() {
+        getInstanceInternal(true);
+        return instance;
+    }
+
+
+    private static TomcatURLStreamHandlerFactory getInstanceInternal(boolean register) {
+        // Double checked locking. OK because instance is volatile.
+        if (instance == null) {
+            synchronized (TomcatURLStreamHandlerFactory.class) {
+                if (instance == null) {
+                    instance = new TomcatURLStreamHandlerFactory(register);
+                }
+            }
+        }
+        return instance;
+    }
+
+
+    private final boolean registered;
+
+    // List of factories for application defined stream handler factories.
+    private final List<URLStreamHandlerFactory> userFactories =
+            new CopyOnWriteArrayList<>();
+
+    /**
+     * Register this factory with the JVM. May be called more than once. The
+     * implementation ensures that registration only occurs once.
+     *
+     * @return <code>true</code> if the factory is already registered with the
+     *         JVM or was successfully registered as a result of this call.
+     *         <code>false</code> if the factory was disabled prior to this
+     *         call.
+     */
+    public static boolean register() {
+        return getInstanceInternal(true).isRegistered();
+    }
+
+
+    /**
+     * Prevent this this factory from registering with the JVM. May be called
+     * more than once.
+     *
+     * @return <code>true</code> if the factory is already disabled or was
+     *         successfully disabled as a result of this call.
+     *         <code>false</code> if the factory was already registered prior
+     *         to this call.
+     */
+    public static boolean disable() {
+        return !getInstanceInternal(false).isRegistered();
+    }
+
+
+    /**
+     * Release references to any user provided factories that have been loaded
+     * using the provided class loader. Called during web application stop to
+     * prevent memory leaks.
+     *
+     * @param classLoader The class loader to release
+     */
+    public static void release(ClassLoader classLoader) {
+        if (instance == null) {
+            return;
+        }
+        List<URLStreamHandlerFactory> factories = instance.userFactories;
+        for (URLStreamHandlerFactory factory : factories) {
+            ClassLoader factoryLoader = factory.getClass().getClassLoader();
+            while (factoryLoader != null) {
+                if (classLoader.equals(factoryLoader)) {
+                    // Implementation note: userFactories is a
+                    // CopyOnWriteArrayList, so items are removed with
+                    // List.remove() instead of usual Iterator.remove()
+                    factories.remove(factory);
+                    break;
+                }
+                factoryLoader = factoryLoader.getParent();
+            }
+        }
+    }
+
+
+    private TomcatURLStreamHandlerFactory(boolean register) {
+        // Hide default constructor
+        // Singleton pattern to ensure there is only one instance of this
+        // factory
+        this.registered = register;
+        if (register) {
+            URL.setURLStreamHandlerFactory(this);
+        }
+    }
+
+
+    public boolean isRegistered() {
+        return registered;
+    }
+
+
+    /**
+     * Since the JVM only allows a single call to
+     * {@link URL#setURLStreamHandlerFactory(URLStreamHandlerFactory)} and
+     * Tomcat needs to register a handler, provide a mechanism to allow
+     * applications to register their own handlers.
+     *
+     * @param factory The user provided factory to add to the factories Tomcat
+     *                has already registered
+     */
+    public void addUserFactory(URLStreamHandlerFactory factory) {
+        userFactories.add(factory);
+    }
+
+
+    @Override
+    public URLStreamHandler createURLStreamHandler(String protocol) {
+
+        // Tomcat's handler always takes priority so applications can't override
+        // it.
+        if (WAR_PROTOCOL.equals(protocol)) {
+            return new Handler();
+        } else if (CLASSPATH_PROTOCOL.equals(protocol)) {
+            return new ClasspathURLStreamHandler();
+        }
+
+        // Application handlers
+        for (URLStreamHandlerFactory factory : userFactories) {
+            URLStreamHandler handler =
+                factory.createURLStreamHandler(protocol);
+            if (handler != null) {
+                return handler;
+            }
+        }
+
+        // Unknown protocol
+        return null;
+    }
+}
diff --git a/res/META-INF/catalina.jar/services/java.net.spi.URLStreamHandlerProvider b/res/META-INF/catalina.jar/services/java.net.spi.URLStreamHandlerProvider
deleted file mode 100644
index 60438bdb23..0000000000
--- a/res/META-INF/catalina.jar/services/java.net.spi.URLStreamHandlerProvider
+++ /dev/null
@@ -1,16 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.
-# The ASF licenses this file to You under the Apache License, Version 2.0
-# (the "License"); you may not use this file except in compliance with
-# the License.  You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-org.apache.catalina.webresources.TomcatURLStreamHandlerProvider
\ No newline at end of file
diff --git a/res/META-INF/tomcat-embed-core.jar/services/java.net.spi.URLStreamHandlerProvider b/res/META-INF/tomcat-embed-core.jar/services/java.net.spi.URLStreamHandlerProvider
deleted file mode 100644
index 60438bdb23..0000000000
--- a/res/META-INF/tomcat-embed-core.jar/services/java.net.spi.URLStreamHandlerProvider
+++ /dev/null
@@ -1,16 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.
-# The ASF licenses this file to You under the Apache License, Version 2.0
-# (the "License"); you may not use this file except in compliance with
-# the License.  You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-org.apache.catalina.webresources.TomcatURLStreamHandlerProvider
\ No newline at end of file
diff --git a/test/META-INF/services/java.net.spi.URLStreamHandlerProvider b/test/META-INF/services/java.net.spi.URLStreamHandlerProvider
deleted file mode 100644
index e0b27f914f..0000000000
--- a/test/META-INF/services/java.net.spi.URLStreamHandlerProvider
+++ /dev/null
@@ -1,17 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.
-# The ASF licenses this file to You under the Apache License, Version 2.0
-# (the "License"); you may not use this file except in compliance with
-# the License.  You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Handler required when running tests
-org.apache.catalina.webresources.TomcatURLStreamHandlerProvider
\ No newline at end of file
diff --git a/test/org/apache/catalina/webresources/TestClasspathUrlStreamHandler.java b/test/org/apache/catalina/webresources/TestClasspathUrlStreamHandler.java
index 9df2b90fa3..f1bb097b37 100644
--- a/test/org/apache/catalina/webresources/TestClasspathUrlStreamHandler.java
+++ b/test/org/apache/catalina/webresources/TestClasspathUrlStreamHandler.java
@@ -22,10 +22,16 @@ import java.net.URL;
 import java.util.Properties;
 
 import org.junit.Assert;
+import org.junit.BeforeClass;
 import org.junit.Test;
 
 public class TestClasspathUrlStreamHandler {
 
+    @BeforeClass
+    public static void setup() {
+        TomcatURLStreamHandlerFactory.getInstance();
+    }
+
     @Test
     public void testClasspathURL01() throws IOException {
         URL u = new URL("classpath:/org/apache/catalina/webresources/LocalStrings.properties");
diff --git a/test/org/apache/catalina/webresources/TestJarWarResourceSet.java b/test/org/apache/catalina/webresources/TestJarWarResourceSet.java
index ed5b29fd2f..be5d98f87a 100644
--- a/test/org/apache/catalina/webresources/TestJarWarResourceSet.java
+++ b/test/org/apache/catalina/webresources/TestJarWarResourceSet.java
@@ -19,6 +19,7 @@ package org.apache.catalina.webresources;
 import java.io.File;
 
 import org.junit.Assert;
+import org.junit.Before;
 import org.junit.Test;
 
 import org.apache.catalina.Context;
@@ -29,6 +30,12 @@ import org.apache.catalina.startup.TomcatBaseTest;
 
 public class TestJarWarResourceSet extends TomcatBaseTest {
 
+    @Before
+    public void register() {
+        TomcatURLStreamHandlerFactory.register();
+    }
+
+
     @Test
     public void testJarWarMetaInf() throws LifecycleException  {
         Tomcat tomcat = getTomcatInstance();
diff --git a/java/org/apache/catalina/webresources/TomcatURLStreamHandlerProvider.java b/test/org/apache/catalina/webresources/TestTomcatURLStreamHandlerFactory.java
similarity index 56%
rename from java/org/apache/catalina/webresources/TomcatURLStreamHandlerProvider.java
rename to test/org/apache/catalina/webresources/TestTomcatURLStreamHandlerFactory.java
index 6be9781506..b999c8be71 100644
--- a/java/org/apache/catalina/webresources/TomcatURLStreamHandlerProvider.java
+++ b/test/org/apache/catalina/webresources/TestTomcatURLStreamHandlerFactory.java
@@ -17,24 +17,27 @@
 package org.apache.catalina.webresources;
 
 import java.net.URLStreamHandler;
-import java.net.spi.URLStreamHandlerProvider;
+import java.net.URLStreamHandlerFactory;
 
-import org.apache.catalina.webresources.war.Handler;
+import org.junit.Before;
+import org.junit.Test;
 
-public class TomcatURLStreamHandlerProvider extends URLStreamHandlerProvider {
-
-    private static final String WAR_PROTOCOL = "war";
-    private static final String CLASSPATH_PROTOCOL = "classpath";
-
-    @Override
-    public URLStreamHandler createURLStreamHandler(String protocol) {
-        if (WAR_PROTOCOL.equals(protocol)) {
-            return new Handler();
-        } else if (CLASSPATH_PROTOCOL.equals(protocol)) {
-            return new ClasspathURLStreamHandler();
-        }
+public class TestTomcatURLStreamHandlerFactory {
 
+    @Before
+    public void register() {
+        TomcatURLStreamHandlerFactory.register();
+    }
 
-        return null;
+    @Test
+    public void testUserFactory() throws Exception {
+        URLStreamHandlerFactory factory = new URLStreamHandlerFactory() {
+            @Override
+            public URLStreamHandler createURLStreamHandler(String protocol) {
+                return null;
+            }
+        };
+        TomcatURLStreamHandlerFactory.getInstance().addUserFactory(factory);
+        TomcatURLStreamHandlerFactory.release(factory.getClass().getClassLoader());
     }
-}
+}
\ No newline at end of file
diff --git a/test/org/apache/catalina/webresources/war/TestHandler.java b/test/org/apache/catalina/webresources/war/TestHandler.java
index 0e3ac88a48..c4b72bee15 100644
--- a/test/org/apache/catalina/webresources/war/TestHandler.java
+++ b/test/org/apache/catalina/webresources/war/TestHandler.java
@@ -21,10 +21,19 @@ import java.net.URL;
 import java.net.URLConnection;
 
 import org.junit.Assert;
+import org.junit.Before;
 import org.junit.Test;
 
+import org.apache.catalina.webresources.TomcatURLStreamHandlerFactory;
+
 public class TestHandler {
 
+    @Before
+    public void register() {
+        TomcatURLStreamHandlerFactory.register();
+    }
+
+
     @Test
     public void testUrlFileInJarInWar() throws Exception {
         doTestUrl("jar:war:", "*/WEB-INF/lib/test.jar!/META-INF/resources/index.html");
diff --git a/test/org/apache/catalina/webresources/war/TestWarURLConnection.java b/test/org/apache/catalina/webresources/war/TestWarURLConnection.java
index 1d82530ce9..f005115824 100644
--- a/test/org/apache/catalina/webresources/war/TestWarURLConnection.java
+++ b/test/org/apache/catalina/webresources/war/TestWarURLConnection.java
@@ -21,10 +21,19 @@ import java.net.URL;
 import java.net.URLConnection;
 
 import org.junit.Assert;
+import org.junit.Before;
 import org.junit.Test;
 
+import org.apache.catalina.webresources.TomcatURLStreamHandlerFactory;
+
 public class TestWarURLConnection {
 
+    @Before
+    public void register() {
+        TomcatURLStreamHandlerFactory.register();
+    }
+
+
     @Test
     public void testContentLength() throws Exception {
         File f = new File("test/webresources/war-url-connection.war");
diff --git a/test/org/apache/tomcat/util/buf/TesterUriUtilBase.java b/test/org/apache/tomcat/util/buf/TesterUriUtilBase.java
index bad8b2f685..9980669aa2 100644
--- a/test/org/apache/tomcat/util/buf/TesterUriUtilBase.java
+++ b/test/org/apache/tomcat/util/buf/TesterUriUtilBase.java
@@ -23,12 +23,15 @@ import java.net.URL;
 import org.junit.Assert;
 import org.junit.Test;
 
+import org.apache.catalina.webresources.TomcatURLStreamHandlerFactory;
+
 public abstract class TesterUriUtilBase {
 
     private final String separator;
 
     protected TesterUriUtilBase(String separator) {
         this.separator = separator;
+        TomcatURLStreamHandlerFactory.register();
         System.setProperty("org.apache.tomcat.util.buf.UriUtil.WAR_SEPARATOR", separator);
     }
 
diff --git a/test/org/apache/tomcat/util/file/TestConfigFileLoader.java b/test/org/apache/tomcat/util/file/TestConfigFileLoader.java
index d87c3de17f..5271e778da 100644
--- a/test/org/apache/tomcat/util/file/TestConfigFileLoader.java
+++ b/test/org/apache/tomcat/util/file/TestConfigFileLoader.java
@@ -27,11 +27,13 @@ import org.junit.BeforeClass;
 import org.junit.Test;
 
 import org.apache.catalina.startup.CatalinaBaseConfigurationSource;
+import org.apache.catalina.webresources.TomcatURLStreamHandlerFactory;
 
 public class TestConfigFileLoader {
 
     @BeforeClass
     public static void setup() {
+        TomcatURLStreamHandlerFactory.getInstance();
         System.setProperty("catalina.base", "");
         ConfigFileLoader.setSource(new CatalinaBaseConfigurationSource(new File(System.getProperty("catalina.base")), null));
     }
diff --git a/test/org/apache/tomcat/util/scan/TestAbstractInputStreamJar.java b/test/org/apache/tomcat/util/scan/TestAbstractInputStreamJar.java
index 278ea23046..b6f96e2b17 100644
--- a/test/org/apache/tomcat/util/scan/TestAbstractInputStreamJar.java
+++ b/test/org/apache/tomcat/util/scan/TestAbstractInputStreamJar.java
@@ -22,13 +22,21 @@ import java.io.InputStream;
 import java.net.URL;
 
 import org.junit.Assert;
+import org.junit.Before;
 import org.junit.Test;
 
 import org.apache.catalina.util.IOTools;
+import org.apache.catalina.webresources.TomcatURLStreamHandlerFactory;
 import org.apache.tomcat.Jar;
 
 public class TestAbstractInputStreamJar {
 
+    @Before
+    public void register() {
+        TomcatURLStreamHandlerFactory.register();
+    }
+
+
     @Test
     public void testNestedJarGetInputStream() throws Exception {
         File f = new File("test/webresources/war-url-connection.war");
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index 3f3e4e70e2..feaabd8985 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -129,6 +129,11 @@
         so that the provider configuration file required by Tomcat's custom URL
         protocol for WAR files is retained when adding OSGi meta-data. (markt)
       </fix>
+      <update>
+        Revert switch to using the ServiceLoader mechanism to load the custom URL
+        protocol handlers that Tomcat uses. The original system property based
+        approach has been restored. (markt)
+      </update>
     </changelog>
   </subsection>
   <subsection name="Coyote">


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org