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

rmaucher pushed a commit to branch 11.0.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit eb17a0dfa3f5c242f60874a9a8e13f28e5883164
Author: opencode <[email protected]>
AuthorDate: Wed Oct 14 12:19:29 2026 +0200

    Ignore incomplete tag-plugin entries in TagPluginParser.addPlugin()
    
    The parser registers addCallMethod for <tag-plugin> with two parameters
    taken from the child element bodies. CallMethodRule always invokes the
    method when it expects more than one parameter, passing null for
    parameters whose element is absent. As a result, a <tag-plugin> element
    that omitted <tag-class> or <plugin-class> stored a map entry with a
    null key or value.
    
    The sole consumer, Jasper's TagPluginManager, then either called
    loadClass(null), which produced a raw NullPointerException surfaced as
    an unhelpful JasperException during JSP translation, or silently stored
    an entry under a null key that could never match a tag handler class.
    
    Fix this by ignoring entries with a null or empty tag class or plugin
    class and logging a localized warning via StringManager, using a new
    resource bundle for the org.apache.tomcat.util.descriptor.tagplugin
    package. Complete entries in the same descriptor are still registered.
    Document the behaviour in the addPlugin() Javadoc. Add tests covering
    direct calls with missing values and the parsing of a descriptor
    mixing incomplete and complete entries.
---
 .../descriptor/tagplugin/LocalStrings.properties   | 16 +++++
 .../util/descriptor/tagplugin/TagPluginParser.java | 12 +++-
 .../tagplugin/TestTagPluginParser-malformed.xml    | 37 ++++++++++
 .../descriptor/tagplugin/TestTagPluginParser.java  | 80 ++++++++++++++++++++++
 4 files changed, 144 insertions(+), 1 deletion(-)

diff --git 
a/java/org/apache/tomcat/util/descriptor/tagplugin/LocalStrings.properties 
b/java/org/apache/tomcat/util/descriptor/tagplugin/LocalStrings.properties
new file mode 100644
index 0000000000..73e7bb96f2
--- /dev/null
+++ b/java/org/apache/tomcat/util/descriptor/tagplugin/LocalStrings.properties
@@ -0,0 +1,16 @@
+# 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.
+
+tagPluginParser.invalidPlugin=Ignoring the <tag-plugin> element with missing 
tag-class [{0}] and/or plugin-class [{1}]
diff --git 
a/java/org/apache/tomcat/util/descriptor/tagplugin/TagPluginParser.java 
b/java/org/apache/tomcat/util/descriptor/tagplugin/TagPluginParser.java
index 994ae2952a..561506b67a 100644
--- a/java/org/apache/tomcat/util/descriptor/tagplugin/TagPluginParser.java
+++ b/java/org/apache/tomcat/util/descriptor/tagplugin/TagPluginParser.java
@@ -30,6 +30,7 @@ import org.apache.tomcat.util.descriptor.DigesterFactory;
 import org.apache.tomcat.util.descriptor.XmlErrorHandler;
 import org.apache.tomcat.util.digester.Digester;
 import org.apache.tomcat.util.digester.RuleSet;
+import org.apache.tomcat.util.res.StringManager;
 import org.xml.sax.InputSource;
 import org.xml.sax.SAXException;
 
@@ -38,6 +39,7 @@ import org.xml.sax.SAXException;
  */
 public class TagPluginParser {
     private final Log log = LogFactory.getLog(TagPluginParser.class); // must 
not be static
+    private static final StringManager sm = 
StringManager.getManager(TagPluginParser.class);
     private static final String PREFIX = "tag-plugins/tag-plugin";
     private final Digester digester;
     private final Map<String,String> plugins = new HashMap<>();
@@ -83,12 +85,20 @@ public class TagPluginParser {
     }
 
     /**
-     * Registers a plugin class for the given tag class.
+     * Registers a plugin class for the given tag class. Both parameters must
+     * be provided. Note that the parser may pass a {@code null} value for a
+     * parameter that is missing from a <code>&lt;tag-plugin&gt;</code>
+     * element. Such incomplete entries are ignored, with a warning logged.
      *
      * @param tagClass    the tag handler class name. Must not be {@code null}.
      * @param pluginClass the plugin class name. Must not be {@code null}.
      */
     public void addPlugin(String tagClass, String pluginClass) {
+        if (tagClass == null || tagClass.isEmpty() ||
+                pluginClass == null || pluginClass.isEmpty()) {
+            log.warn(sm.getString("tagPluginParser.invalidPlugin", tagClass, 
pluginClass));
+            return;
+        }
         plugins.put(tagClass, pluginClass);
     }
 
diff --git 
a/test/org/apache/tomcat/util/descriptor/tagplugin/TestTagPluginParser-malformed.xml
 
b/test/org/apache/tomcat/util/descriptor/tagplugin/TestTagPluginParser-malformed.xml
new file mode 100644
index 0000000000..e608abcc84
--- /dev/null
+++ 
b/test/org/apache/tomcat/util/descriptor/tagplugin/TestTagPluginParser-malformed.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<tag-plugins>
+    <!-- Missing <plugin-class> -->
+    <tag-plugin>
+        <tag-class>com.example.Tag1</tag-class>
+    </tag-plugin>
+    <!-- Missing <tag-class> -->
+    <tag-plugin>
+        <plugin-class>com.example.Plugin2</plugin-class>
+    </tag-plugin>
+    <!-- Empty <tag-class> -->
+    <tag-plugin>
+        <tag-class/>
+        <plugin-class>com.example.Plugin3</plugin-class>
+    </tag-plugin>
+    <!-- Valid -->
+    <tag-plugin>
+        <tag-class>com.example.Tag4</tag-class>
+        <plugin-class>com.example.Plugin4</plugin-class>
+    </tag-plugin>
+</tag-plugins>
diff --git 
a/test/org/apache/tomcat/util/descriptor/tagplugin/TestTagPluginParser.java 
b/test/org/apache/tomcat/util/descriptor/tagplugin/TestTagPluginParser.java
new file mode 100644
index 0000000000..1b10038019
--- /dev/null
+++ b/test/org/apache/tomcat/util/descriptor/tagplugin/TestTagPluginParser.java
@@ -0,0 +1,80 @@
+/*
+ * 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.tomcat.util.descriptor.tagplugin;
+
+import java.io.File;
+import java.util.Map;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.apache.tomcat.unittest.TesterServletContext;
+
+/**
+ * Test cases for {@link TagPluginParser}.
+ */
+public class TestTagPluginParser {
+
+    @Test
+    public void testAddPluginValid() {
+        TagPluginParser parser = new TagPluginParser(new 
TesterServletContext(), true);
+
+        parser.addPlugin("com.example.Tag", "com.example.Plugin");
+
+        Map<String,String> plugins = parser.getPlugins();
+        Assert.assertEquals(1, plugins.size());
+        Assert.assertEquals("com.example.Plugin", 
plugins.get("com.example.Tag"));
+    }
+
+
+    @Test
+    public void testAddPluginIncompleteIgnored() {
+        TagPluginParser parser = new TagPluginParser(new 
TesterServletContext(), true);
+
+        // Missing parameters arrive as null or empty values from the parser
+        parser.addPlugin(null, "com.example.Plugin");
+        parser.addPlugin("com.example.Tag", null);
+        parser.addPlugin("", "com.example.Plugin");
+        parser.addPlugin("com.example.Tag", "");
+
+        Assert.assertTrue(parser.getPlugins().isEmpty());
+    }
+
+
+    /*
+     * A <tag-plugin> element that omits <tag-class> or <plugin-class> results
+     * in addPlugin() being called with a null parameter. Such incomplete
+     * entries must be ignored rather than stored, while complete entries are
+     * still registered.
+     */
+    @Test
+    public void testParseMalformedDescriptor() throws Exception {
+        TagPluginParser parser = new TagPluginParser(new 
TesterServletContext(), true);
+
+        File file = new File("test/org/apache/tomcat/util/descriptor/"
+                + "tagplugin/TestTagPluginParser-malformed.xml");
+        parser.parse(file.toURI().toURL());
+
+        Map<String,String> plugins = parser.getPlugins();
+        Assert.assertEquals(1, plugins.size());
+        Assert.assertFalse(plugins.containsKey(null));
+        Assert.assertFalse(plugins.containsKey(""));
+        Assert.assertFalse(plugins.containsValue(null));
+        Assert.assertEquals("com.example.Plugin4",
+                plugins.get("com.example.Tag4"));
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to