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]

Reply via email to