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 c46e3bb86db173270d26c7d05830036425f2ba58 Author: opencode <[email protected]> AuthorDate: Wed Oct 14 12:57:19 2026 +0200 Parse implicit TLDs in the TldScanner with the strict rule set JSP.7.3.2 only permits version information and a short name in an implicit.tld file. The web application TLD scanner previously parsed these files with the full TldRuleSet at start-up. That allowed elements which the specification forbids in an implicit TLD to take effect: a <uri> element caused the URI to be registered so that the file could be used for URI based taglib directives, and a <listener> element caused JasperInitializer to register the listener with the context, aborting start-up when the class could not be instantiated. TldScanner now owns a second TldParser built with the existing ImplicitTldRuleSet - the same rule set already used by ImplicitTagLibraryInfo when a tag file is translated - and uses it for resources whose web application path is an implicit.tld below /WEB-INF/tags. An implicit TLD which is not specification compliant is now rejected at scan time: the scanner logs a warning naming the resource and continues, so such a file can no longer register a URI, cache a tag library or contribute listeners, and cannot prevent the web application from starting. If the tag library is actually used via tagdir, the same error is reported at translation time as before. Explicit taglib mappings in web.xml (scanJspConfig) deliberately keep using the lenient parser since an explicit mapping is an administrator decision and <listener> is legitimate in a regular TLD. Also replace the /WEB-INF/tags/ and /implicit.tld literals in scanResourcePaths() with the new WEB_INF_TAGS and IMPLICIT_TLD constants, now used by both code paths. --- .../jasper/resources/LocalStrings.properties | 1 + java/org/apache/jasper/servlet/TldScanner.java | 39 ++++++++++-- test/org/apache/jasper/servlet/TestTldScanner.java | 73 ++++++++++++++++++++++ 3 files changed, 109 insertions(+), 4 deletions(-) diff --git a/java/org/apache/jasper/resources/LocalStrings.properties b/java/org/apache/jasper/resources/LocalStrings.properties index 20441f34f8..334eae9cf1 100644 --- a/java/org/apache/jasper/resources/LocalStrings.properties +++ b/java/org/apache/jasper/resources/LocalStrings.properties @@ -424,6 +424,7 @@ org.apache.jasper.compiler.ELParser.invalidQuoting=The expression [{0}] is not v org.apache.jasper.compiler.ELParser.missingQuote=The expression [{0}] is not valid as it is missing an end quote. org.apache.jasper.compiler.TldCache.servletContextNull=The provided ServletContext was null org.apache.jasper.servlet.JasperInitializer.onStartup=Initializing Jasper for context [{0}] +org.apache.jasper.servlet.TldScanner.implicitTldInvalid=The implicit TLD at resource path [{0}] was ignored as it is not valid: {1} org.apache.jasper.servlet.TldScanner.webxmlAdd=Loading TLD for URI [{1}] from resource path [{0}] org.apache.jasper.servlet.TldScanner.webxmlFailPathDoesNotExist=Failed to process TLD with path [{0}] and URI [{1}]. The specified path does not exist. org.apache.jasper.servlet.TldScanner.webxmlSkip=Skipping load of TLD for URI [{1}] from resource path [{0}] as it has already been defined in <jsp-config> diff --git a/java/org/apache/jasper/servlet/TldScanner.java b/java/org/apache/jasper/servlet/TldScanner.java index b4629758da..6d362e54b7 100644 --- a/java/org/apache/jasper/servlet/TldScanner.java +++ b/java/org/apache/jasper/servlet/TldScanner.java @@ -44,6 +44,7 @@ import org.apache.tomcat.Jar; import org.apache.tomcat.JarScanType; import org.apache.tomcat.JarScanner; import org.apache.tomcat.JarScannerCallback; +import org.apache.tomcat.util.descriptor.tld.ImplicitTldRuleSet; import org.apache.tomcat.util.descriptor.tld.TaglibXml; import org.apache.tomcat.util.descriptor.tld.TldParser; import org.apache.tomcat.util.descriptor.tld.TldResourcePath; @@ -57,8 +58,11 @@ public class TldScanner { private static final String MSG = "org.apache.jasper.servlet.TldScanner"; private static final String TLD_EXT = ".tld"; private static final String WEB_INF = "/WEB-INF/"; + private static final String WEB_INF_TAGS = "/WEB-INF/tags/"; + private static final String IMPLICIT_TLD = "/implicit.tld"; private final ServletContext context; private final TldParser tldParser; + private final TldParser implicitTldParser; private final Map<String,TldResourcePath> uriTldResourcePathMap = new HashMap<>(); private final Map<TldResourcePath,TaglibXml> tldResourcePathTaglibXmlMap = new HashMap<>(); private final List<String> listeners = new ArrayList<>(); @@ -76,6 +80,8 @@ public class TldScanner { this.context = context; this.tldParser = new TldParser(namespaceAware, validation, blockExternal); + this.implicitTldParser = + new TldParser(namespaceAware, validation, new ImplicitTldRuleSet(), blockExternal); } /** @@ -133,6 +139,7 @@ public class TldScanner { */ public void setClassLoader(ClassLoader classLoader) { tldParser.setClassLoader(classLoader); + implicitTldParser.setClassLoader(classLoader); } /** @@ -216,11 +223,21 @@ public class TldScanner { // Skip: JSP.7.3.1 } else if (path.endsWith("/")) { scanResourcePaths(path); - } else if (path.startsWith("/WEB-INF/tags/")) { + } else if (path.startsWith(WEB_INF_TAGS)) { // JSP 7.3.1: in /WEB-INF/tags only consider implicit.tld - if (path.endsWith("/implicit.tld")) { + if (path.endsWith(IMPLICIT_TLD)) { found = true; - parseTld(path); + try { + parseTld(path); + } catch (SAXException e) { + // An implicit TLD that is not specification + // compliant must not prevent the web application + // from starting. It is parsed again when a tag + // from the tag file is used and the error will + // be reported to the developer at that point. + log.warn(Localizer.getMessage( + MSG + ".implicitTldInvalid", path, e.getMessage())); + } } } else if (path.endsWith(TLD_EXT)) { found = true; @@ -271,7 +288,16 @@ public class TldScanner { * @throws SAXException if a parsing error occurs */ protected void parseTld(TldResourcePath path) throws IOException, SAXException { - TaglibXml tld = tldParser.parse(path); + TaglibXml tld; + if (isImplicitTld(path.getWebappPath())) { + // JSP.7.3.2: an implicit TLD only allows version information and + // a short name. The strict rule set rejects everything else, so + // that such a TLD is rejected here just as it is when the tag + // file is translated. + tld = implicitTldParser.parse(path); + } else { + tld = tldParser.parse(path); + } String uri = tld.getUri(); if (uri != null) { if (!uriTldResourcePathMap.containsKey(uri)) { @@ -290,6 +316,11 @@ public class TldScanner { } } + private static boolean isImplicitTld(String webappPath) { + return webappPath != null && webappPath.startsWith(WEB_INF_TAGS) && + webappPath.endsWith(IMPLICIT_TLD); + } + class TldScannerCallback implements JarScannerCallback { private boolean foundJarWithoutTld = false; private boolean foundFileWithoutTld = false; diff --git a/test/org/apache/jasper/servlet/TestTldScanner.java b/test/org/apache/jasper/servlet/TestTldScanner.java index 893f12a144..84804b98df 100644 --- a/test/org/apache/jasper/servlet/TestTldScanner.java +++ b/test/org/apache/jasper/servlet/TestTldScanner.java @@ -21,6 +21,8 @@ import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.net.URI; import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -55,6 +57,77 @@ public class TestTldScanner extends TomcatBaseTest { } + @Test + public void testScanImplicitTldInvalid() throws Exception { + // JSP.7.3.2 only allows version information and a short name in an + // implicit.tld. Elements such as <uri>, <listener> and <tag> must be + // rejected, so scanning must not register anything from this file. + Tomcat tomcat = getTomcatInstance(); + File appDir = new File(getTemporaryDirectory(), "implicit-tld-invalid"); + createImplicitTld(appDir, "<uri>http://tomcat.apache.org/from-implicit-tld</uri>\n" + + " <listener>\n" + + " <listener-class>com.example.TesterListener</listener-class>\n" + + " </listener>\n" + + " <tag>\n" + + " <name>Foo</name>\n" + + " <tag-class>com.example.TesterTag</tag-class>\n" + + " <body-content>empty</body-content>\n" + + " </tag>"); + Context context = tomcat.addWebapp(null, "/test", appDir.getAbsolutePath()); + tomcat.start(); + + TldScanner scanner = + new TldScanner(context.getServletContext(), true, true, true); + scanner.scan(); + + Assert.assertNull(scanner.getUriTldResourcePathMap().get( + "http://tomcat.apache.org/from-implicit-tld")); + Assert.assertEquals(0, scanner.getListeners().size()); + Assert.assertEquals(0, scanner.getTldResourcePathTaglibXmlMap().size()); + } + + + @Test + public void testScanImplicitTldValid() throws Exception { + // A specification compliant implicit.tld only contributes the short + // name which is used for tagdir based lookups, not for URI based ones. + Tomcat tomcat = getTomcatInstance(); + File appDir = new File(getTemporaryDirectory(), "implicit-tld-valid"); + createImplicitTld(appDir, null); + Context context = tomcat.addWebapp(null, "/test", appDir.getAbsolutePath()); + tomcat.start(); + + TldScanner scanner = + new TldScanner(context.getServletContext(), true, true, true); + scanner.scan(); + + // The specification compliant file is still parsed and cached but it + // contributes nothing to URI based lookups. + Assert.assertEquals(0, scanner.getUriTldResourcePathMap().size()); + Assert.assertEquals(0, scanner.getListeners().size()); + Assert.assertEquals(1, scanner.getTldResourcePathTaglibXmlMap().size()); + } + + + private static void createImplicitTld(File appDir, String extraElements) throws Exception { + File implicitTld = new File(appDir, "WEB-INF/tags/display/implicit.tld"); + Files.createDirectories(implicitTld.getParentFile().toPath()); + StringBuilder content = new StringBuilder( + "<taglib xmlns=\"http://java.sun.com/xml/ns/javaee\"\n" + + " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" + + " xsi:schemaLocation=\"http://java.sun.com/xml/ns/javaee\n" + + " http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd\"\n" + + " version=\"2.1\">\n" + + " <tlib-version>1.0</tlib-version>\n" + + " <short-name>display</short-name>\n"); + if (extraElements != null) { + content.append(" ").append(extraElements).append('\n'); + } + content.append("</taglib>\n"); + Files.writeString(implicitTld.toPath(), content, StandardCharsets.UTF_8); + } + + @Test public void testBug55807() throws Exception { Tomcat tomcat = getTomcatInstance(); --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
