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 bab89e9ac2810d5199eca99775adbb881cc5d4f8
Author: opencode <[email protected]>
AuthorDate: Sun Oct 18 23:15:46 2026 +0200

    Match the JSP namespace exactly when detecting JSP documents
    
    ParserController.hasJspRoot() used a regionMatches() prefix comparison
    when checking the namespace bound to the root element's prefix. A
    namespace that merely started with "http://java.sun.com/JSP/Page";, such
    as "http://java.sun.com/JSP/PageExtra";, incorrectly triggered parsing of
    the page as a JSP document. Such pages were silently miscompiled as XML:
    a spurious XML declaration was prepended to the response, whitespace
    text between elements was removed and the namespace declaration was
    dropped from the root element.
    
    Read the full quoted attribute value and compare it with the JSP
    namespace using String.equals(), as the rest of Jasper already does when
    comparing this URI.
    
    Add tests that cover detection of a root element bound to the exact JSP
    namespace using both the jsp prefix and an arbitrary prefix, and
    non-detection when the namespace only starts with the JSP namespace.
---
 .../apache/jasper/compiler/ParserController.java   |  6 +-
 .../jasper/compiler/TestParserController.java      | 67 ++++++++++++++++++++++
 2 files changed, 72 insertions(+), 1 deletion(-)

diff --git a/java/org/apache/jasper/compiler/ParserController.java 
b/java/org/apache/jasper/compiler/ParserController.java
index 7dbe122479..e9852b73ff 100644
--- a/java/org/apache/jasper/compiler/ParserController.java
+++ b/java/org/apache/jasper/compiler/ParserController.java
@@ -557,8 +557,12 @@ public class ParserController implements TagConstants {
                 index++;
             } while (index < root.length() && 
Character.isWhitespace(root.charAt(index)));
             if (index < root.length() && (root.charAt(index) == '"' || 
root.charAt(index) == '\'')) {
+                char quote = root.charAt(index);
                 index++;
-                return root.regionMatches(index, JSP_URI, 0, JSP_URI.length());
+                int end = root.indexOf(quote, index);
+                if (end > index) {
+                    return JSP_URI.equals(root.substring(index, end));
+                }
             }
         }
 
diff --git a/test/org/apache/jasper/compiler/TestParserController.java 
b/test/org/apache/jasper/compiler/TestParserController.java
index 51594b2512..09f33c6027 100644
--- a/test/org/apache/jasper/compiler/TestParserController.java
+++ b/test/org/apache/jasper/compiler/TestParserController.java
@@ -16,9 +16,14 @@
  */
 package org.apache.jasper.compiler;
 
+import java.io.File;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+
 import org.junit.Assert;
 import org.junit.Test;
 
+import org.apache.catalina.startup.Tomcat;
 import org.apache.catalina.startup.TomcatBaseTest;
 import org.apache.tomcat.util.buf.ByteChunk;
 
@@ -40,4 +45,66 @@ public class TestParserController extends TomcatBaseTest {
         Assert.assertTrue(result, result.contains("The include [a b.jsp] is 
invalid"));
         Assert.assertFalse(result, result.contains("Cannot invoke"));
     }
+
+    @Test
+    public void testJspRootDetection() throws Exception {
+        // The pages for these tests are generated rather than stored with the
+        // tests so that the output, which is compared exactly, always uses
+        // Unix line endings for the template text
+        Tomcat tomcat = getTomcatInstance();
+        File appDir = new File(getTemporaryDirectory(), "root-detection");
+        Assert.assertTrue(appDir.mkdirs() || appDir.isDirectory());
+
+        // The root element may use any prefix as long as the prefix is bound
+        // to the exact JSP namespace URI
+        Files.writeString(new File(appDir, "jsp.jsp").toPath(),
+                "<jsp:root xmlns:jsp=\"" + TagConstants.JSP_URI + "\" 
version=\"2.0\">\n" +
+                        "<jsp:body>OK</jsp:body>\n</jsp:root>\n", 
StandardCharsets.UTF_8);
+        Files.writeString(new File(appDir, "other.jsp").toPath(),
+                "<mypfx:root xmlns:mypfx=\"" + TagConstants.JSP_URI + "\" 
version=\"2.0\">\n" +
+                        "<mypfx:body>OK</mypfx:body>\n</mypfx:root>\n", 
StandardCharsets.UTF_8);
+
+        tomcat.addWebapp(null, "/test", appDir.getAbsolutePath());
+        tomcat.start();
+
+        // Both pages must be parsed as JSP documents. They are handled as XML
+        // syntax so, as the output below shows, only the body content is
+        // written; the whitespace text between the elements is removed
+        ByteChunk res = new ByteChunk();
+        int sc = getUrl("http://localhost:"; + getPort() + "/test/jsp.jsp", 
res, null);
+        Assert.assertEquals(200, sc);
+        Assert.assertEquals("OK", res.toString());
+
+        res = new ByteChunk();
+        sc = getUrl("http://localhost:"; + getPort() + "/test/other.jsp", res, 
null);
+        Assert.assertEquals(200, sc);
+        Assert.assertEquals("OK", res.toString());
+    }
+
+    @Test
+    public void testRootPrefixNamespaceIsNotJspDocument() throws Exception {
+        // A namespace that only starts with the JSP namespace URI must not
+        // trigger parsing as a JSP document
+        Tomcat tomcat = getTomcatInstance();
+        File appDir = new File(getTemporaryDirectory(), "root-prefix");
+        Assert.assertTrue(appDir.mkdirs() || appDir.isDirectory());
+        Files.writeString(new File(appDir, "prefix.jsp").toPath(),
+                "<foo:root xmlns:foo=\"" + TagConstants.JSP_URI + 
"PageExtra\">\n" +
+                        "<p>hello</p>\n</foo:root>\n", StandardCharsets.UTF_8);
+
+        tomcat.addWebapp(null, "/test", appDir.getAbsolutePath());
+        tomcat.start();
+
+        ByteChunk res = new ByteChunk();
+        int sc = getUrl("http://localhost:"; + getPort() + "/test/prefix.jsp", 
res, null);
+
+        Assert.assertEquals(200, sc);
+
+        // The page must be handled as standard syntax: the template text,
+        // including the line breaks written above, is output unchanged and no
+        // XML declaration is added
+        String result = res.toString();
+        Assert.assertTrue(result, 
result.contains("PageExtra\">\n<p>hello</p>"));
+        Assert.assertFalse(result, result.contains("<?xml"));
+    }
 }


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

Reply via email to