This is an automated email from the ASF dual-hosted git repository. rmaucher pushed a commit to branch 10.1.x in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit c3d2e676b3342ff58c0b60efc201dbd323ba8312 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><tag-plugin></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]
