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 d7ce66ba27be03469e91bb9073fe74ddfeb63e72 Author: opencode <[email protected]> AuthorDate: Sun Oct 18 22:16:49 2026 +0200 Fix the jsp:attribute trim loop skipping nodes after removal When removing white-space only template text nodes from the body of a jsp:attribute action while parsing a JSP document, the loop in JspDocumentParser.endElement() did not re-examine the node that was shifted into the vacated position after a removal. Adjacent template text siblings occur in practice when the attribute body contains CDATA sections, because the startCDATA/endCDATA handling flushes the buffered characters into a template text node without creating a separating node. For such bodies the skipped node could be a second white-space only text node that then remained in the body, or the final text node which consequently was not trimmed when trim was true. Re-examine the shifted node after each removal so every text node receives the treatment required by the specification. Add a regression test using CDATA sections in jsp:attribute bodies. Found by code review. --- .../apache/jasper/compiler/JspDocumentParser.java | 3 ++ .../jasper/compiler/TestJspDocumentParser.java | 23 ++++++++++++++ test/webapp/jsp/document/named-attribute-trim.jspx | 37 ++++++++++++++++++++++ webapps/docs/changelog.xml | 10 ++++++ 4 files changed, 73 insertions(+) diff --git a/java/org/apache/jasper/compiler/JspDocumentParser.java b/java/org/apache/jasper/compiler/JspDocumentParser.java index 2730220d6f..7eaea7fb33 100644 --- a/java/org/apache/jasper/compiler/JspDocumentParser.java +++ b/java/org/apache/jasper/compiler/JspDocumentParser.java @@ -548,6 +548,9 @@ class JspDocumentParser extends DefaultHandler2 implements TagConstants { } else { if (((Node.TemplateText) subElem).isAllSpace()) { subElems.remove(subElem); + // Re-examine the element that was shifted into this + // position by the removal above + i--; } } } diff --git a/test/org/apache/jasper/compiler/TestJspDocumentParser.java b/test/org/apache/jasper/compiler/TestJspDocumentParser.java index 8eac2bf2c3..db377dbdbe 100644 --- a/test/org/apache/jasper/compiler/TestJspDocumentParser.java +++ b/test/org/apache/jasper/compiler/TestJspDocumentParser.java @@ -85,6 +85,29 @@ public class TestJspDocumentParser extends TomcatBaseTest { Assert.assertEquals(HttpServletResponse.SC_OK, rc); } + @Test + public void testNamedAttributeTrimCdata() throws Exception { + getTomcatInstanceTestWebapp(false, true); + + ByteChunk bc = new ByteChunk(); + int rc = getUrl("http://localhost:" + getPort() + "/test/jsp/document/named-attribute-trim.jspx", bc, null); + + Assert.assertEquals(HttpServletResponse.SC_OK, rc); + + String result = bc.toString(); + + // White-space only text nodes between the other body elements must be + // removed and the final text node must be trimmed + Assert.assertTrue(result, result.contains("<e1 a=\"x tail\"/>")); + Assert.assertTrue(result, result.contains("<e2 a=\"x\"/>")); + Assert.assertTrue(result, result.contains("<e3 a=\"xy\"/>")); + Assert.assertTrue(result, result.contains("<e4 a=\"x y\"/>")); + // With trim set to false, leading and trailing white-space only text + // nodes must be kept verbatim + Assert.assertTrue(result, result.contains("<t5 a=\" \"/>")); + Assert.assertTrue(result, result.contains("<t6 a=\"x tail \"/>")); + } + @Test public void testSchemaValidation() throws Exception { getTomcatInstanceTestWebapp(false, true); diff --git a/test/webapp/jsp/document/named-attribute-trim.jspx b/test/webapp/jsp/document/named-attribute-trim.jspx new file mode 100644 index 0000000000..5422dc524e --- /dev/null +++ b/test/webapp/jsp/document/named-attribute-trim.jspx @@ -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. +--> +<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.0"> + <!-- + Regression tests for the handling of adjacent template text nodes - + produced by CDATA sections - in the body of a jsp:attribute action. + Expected results are given in comments below. Each element name encodes + the trim setting: e* for trim="true" (the default), t* for trim="false". + --> + <!-- Middle white-space only node removed, trailing node trimmed: "x tail" --> + <jsp:element name="e1"><jsp:attribute name="a"><jsp:text>x</jsp:text><![CDATA[ ]]><![CDATA[ tail ]]></jsp:attribute></jsp:element> + <!-- Both consecutive white-space only middle nodes removed: "x" --> + <jsp:element name="e2"><jsp:attribute name="a"><jsp:text>x</jsp:text><![CDATA[ ]]><![CDATA[ ]]></jsp:attribute></jsp:element> + <!-- Second of two consecutive white-space only middle nodes removed: "xy" --> + <jsp:element name="e3"><jsp:attribute name="a"><jsp:text>x</jsp:text><![CDATA[ ]]><![CDATA[ ]]><jsp:text>y</jsp:text></jsp:attribute></jsp:element> + <!-- Single CDATA between text nodes, trailing node trimmed: "x y" --> + <jsp:element name="e4"><jsp:attribute name="a">x<![CDATA[ ]]> y </jsp:attribute></jsp:element> + <!-- Leading and trailing white-space only nodes kept verbatim: " " --> + <jsp:element name="t5"><jsp:attribute name="a" trim="false"><![CDATA[ ]]><![CDATA[ ]]></jsp:attribute></jsp:element> + <!-- Middle node removed, trailing node kept verbatim: "x tail " --> + <jsp:element name="t6"><jsp:attribute name="a" trim="false">x<![CDATA[ ]]><![CDATA[ tail ]]></jsp:attribute></jsp:element> +</jsp:root> diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml index f5056106ad..daf328013e 100644 --- a/webapps/docs/changelog.xml +++ b/webapps/docs/changelog.xml @@ -411,6 +411,16 @@ silently omitted from processing. Option parsing now stops at the first full stop argument wherever it appears. (remm) </fix> + <fix> + When removing white-space only template text nodes from the body of a + <code>jsp:attribute</code> action while parsing a JSP document, the + node that was shifted into the vacated position is now re-examined. + Previously it was skipped, which, for bodies containing adjacent + template text nodes such as those produced by CDATA sections, could + leave a white-space only text node in the body or prevent the final + text node from being trimmed when <code>trim</code> was + <code>true</code>. (remm) + </fix> </changelog> </subsection> <subsection name="WebSocket"> --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
