Author: markt Date: Tue Oct 19 13:21:05 2010 New Revision: 1024229 URL: http://svn.apache.org/viewvc?rev=1024229&view=rev Log: Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=49297 Enforce the rules in the JSP specification for parsing the attributes of custom and standard actions that require that the attribute names are unique within an element and that there is whitespace before the attribute name. The whitespace test can be disabled by setting the system property <code>org.apache.jasper.compiler.Parser.STRICT_WHITESPACE</code> to <code>false</code>
Added: tomcat/trunk/java/org/apache/jasper/util/UniqueAttributesImpl.java (with props) tomcat/trunk/test/org/apache/jasper/compiler/TestParserNoStrictWhitespace.java (with props) tomcat/trunk/test/webapp-3.0/bug49297DuplicateAttr.jsp (with props) tomcat/trunk/test/webapp-3.0/bug49297NoSpace.jsp (with props) Modified: tomcat/trunk/java/org/apache/jasper/compiler/Parser.java tomcat/trunk/java/org/apache/jasper/resources/LocalStrings.properties tomcat/trunk/test/org/apache/jasper/compiler/TestParser.java tomcat/trunk/test/webapp-3.0/WEB-INF/tags/echo.tag tomcat/trunk/webapps/docs/changelog.xml tomcat/trunk/webapps/docs/config/systemprops.xml Modified: tomcat/trunk/java/org/apache/jasper/compiler/Parser.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/jasper/compiler/Parser.java?rev=1024229&r1=1024228&r2=1024229&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/jasper/compiler/Parser.java (original) +++ tomcat/trunk/java/org/apache/jasper/compiler/Parser.java Tue Oct 19 13:21:05 2010 @@ -28,6 +28,7 @@ import javax.servlet.jsp.tagext.TagLibra import org.apache.jasper.JasperException; import org.apache.jasper.JspCompilationContext; +import org.apache.jasper.util.UniqueAttributesImpl; import org.xml.sax.Attributes; import org.xml.sax.helpers.AttributesImpl; @@ -74,6 +75,13 @@ class Parser implements TagConstants { private static final String JAVAX_BODY_CONTENT_TEMPLATE_TEXT = "JAVAX_BODY_CONTENT_TEMPLATE_TEXT"; + /* System property that controls if the strict white space rules are + * applied. + */ + private static final boolean STRICT_WHITESPACE = Boolean.valueOf( + System.getProperty( + "org.apache.jasper.compiler.Parser.STRICT_WHITESPACE", + "true")).booleanValue(); /** * The constructor */ @@ -142,11 +150,23 @@ class Parser implements TagConstants { * Attributes ::= (S Attribute)* S? */ Attributes parseAttributes() throws JasperException { - AttributesImpl attrs = new AttributesImpl(); + UniqueAttributesImpl attrs = new UniqueAttributesImpl(); reader.skipSpaces(); - while (parseAttribute(attrs)) - reader.skipSpaces(); + int ws = 1; + + try { + while (parseAttribute(attrs)) { + if (ws == 0 && STRICT_WHITESPACE) { + err.jspError(reader.mark(), + "jsp.error.attribute.nowhitespace"); + } + ws = reader.skipSpaces(); + } + } catch (IllegalArgumentException iae) { + // Duplicate attribute + err.jspError(reader.mark(), "jsp.error.attribute.duplicate"); + } return attrs; } Modified: tomcat/trunk/java/org/apache/jasper/resources/LocalStrings.properties URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/jasper/resources/LocalStrings.properties?rev=1024229&r1=1024228&r2=1024229&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/jasper/resources/LocalStrings.properties (original) +++ tomcat/trunk/java/org/apache/jasper/resources/LocalStrings.properties Tue Oct 19 13:21:05 2010 @@ -347,6 +347,8 @@ jsp.error.attribute.noequal=equal symbol jsp.error.attribute.noquote=quote symbol expected jsp.error.attribute.unterminated=attribute for {0} is not properly terminated jsp.error.attribute.noescape=Attribute value {0} is quoted with {1} which must be escaped when used within the value +jsp.error.attribute.nowhitespace=The JSP specification requires that an attribute name is preceded by whitespace +jsp.error.attribute.duplicate=Attribute qualified names must be unique within an element jsp.error.missing.tagInfo=TagInfo object for {0} is missing from TLD jsp.error.deferredmethodsignaturewithoutdeferredmethod=Cannot specify a method signature if 'deferredMethod' is not 'true' jsp.error.deferredvaluetypewithoutdeferredvalue=Cannot specify a value type if 'deferredValue' is not 'true' @@ -466,3 +468,6 @@ jsp.warning.noJarScanner=Warning: No org # JavacErrorDetail jsp.error.bug48498=Unable to display JSP extract. Probably due to an XML parser bug (see Tomcat bug 48498 for details). + +# UniqueAttributesImpl +jsp.error.duplicateqname=An attribute with duplicate qualified name [{0}] was found. Attribute qualified names must be unique within an element. \ No newline at end of file Added: tomcat/trunk/java/org/apache/jasper/util/UniqueAttributesImpl.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/jasper/util/UniqueAttributesImpl.java?rev=1024229&view=auto ============================================================================== --- tomcat/trunk/java/org/apache/jasper/util/UniqueAttributesImpl.java (added) +++ tomcat/trunk/java/org/apache/jasper/util/UniqueAttributesImpl.java Tue Oct 19 13:21:05 2010 @@ -0,0 +1,87 @@ +/* + * 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.jasper.util; + +import java.util.HashSet; +import java.util.Set; + +import org.apache.jasper.compiler.Localizer; +import org.xml.sax.Attributes; +import org.xml.sax.helpers.AttributesImpl; + +/** + * Wraps the default attributes implementation and ensures that each attribute + * has a unique qname as required by the JSP specification. + */ +public class UniqueAttributesImpl extends AttributesImpl { + + private Set<String> qNames = new HashSet<String>(); + + @Override + public void clear() { + qNames.clear(); + super.clear(); + } + + @Override + public void setAttributes(Attributes atts) { + for (int i = 0; i < atts.getLength(); i++) { + if (!qNames.add(atts.getQName(i))) { + handleDuplicate(atts.getQName(i)); + } + } + super.setAttributes(atts); + } + + @Override + public void addAttribute(String uri, String localName, String qName, + String type, String value) { + if (qNames.add(qName)) { + super.addAttribute(uri, localName, qName, type, value); + } else { + handleDuplicate(qName); + } + } + + @Override + public void setAttribute(int index, String uri, String localName, + String qName, String type, String value) { + qNames.remove(super.getQName(index)); + if (qNames.add(qName)) { + super.setAttribute(index, uri, localName, qName, type, value); + } else { + handleDuplicate(qName); + } + } + + @Override + public void removeAttribute(int index) { + qNames.remove(super.getQName(index)); + super.removeAttribute(index); + } + + @Override + public void setQName(int index, String qName) { + qNames.remove(super.getQName(index)); + super.setQName(index, qName); + } + + private void handleDuplicate(String qName) { + throw new IllegalArgumentException( + Localizer.getMessage("jsp.error.duplicateqname", qName)); + } +} Propchange: tomcat/trunk/java/org/apache/jasper/util/UniqueAttributesImpl.java ------------------------------------------------------------------------------ svn:eol-style = native Modified: tomcat/trunk/test/org/apache/jasper/compiler/TestParser.java URL: http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/jasper/compiler/TestParser.java?rev=1024229&r1=1024228&r2=1024229&view=diff ============================================================================== --- tomcat/trunk/test/org/apache/jasper/compiler/TestParser.java (original) +++ tomcat/trunk/test/org/apache/jasper/compiler/TestParser.java Tue Oct 19 13:21:05 2010 @@ -18,11 +18,17 @@ package org.apache.jasper.compiler; import java.io.File; +import java.util.HashMap; +import java.util.List; import org.apache.catalina.startup.Tomcat; import org.apache.catalina.startup.TomcatBaseTest; import org.apache.tomcat.util.buf.ByteChunk; +/** + * Tests are duplicated in {...@link TestParserNoStrictWhitespace} with the strict + * whitespace parsing disabled. + */ public class TestParser extends TomcatBaseTest { public void testBug48627() throws Exception { @@ -93,8 +99,7 @@ public class TestParser extends TomcatBa public void testBug48668b() throws Exception { Tomcat tomcat = getTomcatInstance(); - File appDir = - new File("test/webapp-3.0"); + File appDir = new File("test/webapp-3.0"); // app dir is relative to server home tomcat.addWebapp(null, "/test", appDir.getAbsolutePath()); @@ -107,6 +112,38 @@ public class TestParser extends TomcatBa assertEcho(result, "01-Hello world</p>#{foo2"); } + public void testBug49297NoSpaceStrict() throws Exception { + Tomcat tomcat = getTomcatInstance(); + + File appDir = new File("test/webapp-3.0"); + // app dir is relative to server home + tomcat.addWebapp(null, "/test", appDir.getAbsolutePath()); + + tomcat.start(); + + int sc = getUrl("http://localhost:" + getPort() + + "/test/bug49297NoSpace.jsp", new ByteChunk(), + new HashMap<String,List<String>>()); + + assertEquals(500, sc); + } + + public void testBug49297DuplicateAttr() throws Exception { + Tomcat tomcat = getTomcatInstance(); + + File appDir = new File("test/webapp-3.0"); + // app dir is relative to server home + tomcat.addWebapp(null, "/test", appDir.getAbsolutePath()); + + tomcat.start(); + + int sc = getUrl("http://localhost:" + getPort() + + "/test/bug49297DuplicateAttr.jsp", new ByteChunk(), + new HashMap<String,List<String>>()); + + assertEquals(500, sc); + } + /** Assertion for text printed by tags:echo */ private static void assertEcho(String result, String expected) { assertTrue(result.indexOf("<p>" + expected + "</p>") > 0); Added: tomcat/trunk/test/org/apache/jasper/compiler/TestParserNoStrictWhitespace.java URL: http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/jasper/compiler/TestParserNoStrictWhitespace.java?rev=1024229&view=auto ============================================================================== --- tomcat/trunk/test/org/apache/jasper/compiler/TestParserNoStrictWhitespace.java (added) +++ tomcat/trunk/test/org/apache/jasper/compiler/TestParserNoStrictWhitespace.java Tue Oct 19 13:21:05 2010 @@ -0,0 +1,163 @@ +/* + * 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.jasper.compiler; + +import java.io.File; +import java.util.HashMap; +import java.util.List; + +import org.apache.catalina.startup.Tomcat; +import org.apache.catalina.startup.TomcatBaseTest; +import org.apache.tomcat.util.buf.ByteChunk; + +/** + * Tests are duplicated in {...@link TestParser} with the strict whitespace parsing + * enabled by default. + */ +public class TestParserNoStrictWhitespace extends TomcatBaseTest { + + @Override + public void setUp() throws Exception { + System.setProperty( + "org.apache.jasper.compiler.Parser.STRICT_WHITESPACE", + "false"); + super.setUp(); + } + + public void testBug48627() throws Exception { + Tomcat tomcat = getTomcatInstance(); + + File appDir = + new File("test/webapp-3.0"); + // app dir is relative to server home + tomcat.addWebapp(null, "/test", appDir.getAbsolutePath()); + + tomcat.start(); + + ByteChunk res = getUrl("http://localhost:" + getPort() + + "/test/bug48nnn/bug48627.jsp"); + + String result = res.toString(); + // Beware of the differences between escaping in JSP attributes and + // in Java Strings + assertEcho(result, "00-\\"); + assertEcho(result, "01-\\"); + } + + public void testBug48668a() throws Exception { + Tomcat tomcat = getTomcatInstance(); + + File appDir = + new File("test/webapp-3.0"); + // app dir is relative to server home + tomcat.addWebapp(null, "/test", appDir.getAbsolutePath()); + + tomcat.start(); + + ByteChunk res = getUrl("http://localhost:" + getPort() + + "/test/bug48nnn/bug48668a.jsp"); + String result = res.toString(); + assertEcho(result, "00-Hello world</p>#{foo.bar}"); + assertEcho(result, "01-Hello world</p>${foo.bar}"); + assertEcho(result, "10-Hello ${'foo.bar}"); + assertEcho(result, "11-Hello ${'foo.bar}"); + assertEcho(result, "12-Hello #{'foo.bar}"); + assertEcho(result, "13-Hello #{'foo.bar}"); + assertEcho(result, "14-Hello ${'foo}"); + assertEcho(result, "15-Hello ${'foo}"); + assertEcho(result, "16-Hello #{'foo}"); + assertEcho(result, "17-Hello #{'foo}"); + assertEcho(result, "18-Hello ${'foo.bar}"); + assertEcho(result, "19-Hello ${'foo.bar}"); + assertEcho(result, "20-Hello #{'foo.bar}"); + assertEcho(result, "21-Hello #{'foo.bar}"); + assertEcho(result, "30-Hello ${'foo}"); + assertEcho(result, "31-Hello ${'foo}"); + assertEcho(result, "32-Hello #{'foo}"); + assertEcho(result, "33-Hello #{'foo}"); + assertEcho(result, "34-Hello ${'foo}"); + assertEcho(result, "35-Hello ${'foo}"); + assertEcho(result, "36-Hello #{'foo}"); + assertEcho(result, "37-Hello #{'foo}"); + assertEcho(result, "40-Hello ${'foo}"); + assertEcho(result, "41-Hello ${'foo}"); + assertEcho(result, "42-Hello #{'foo}"); + assertEcho(result, "43-Hello #{'foo}"); + assertEcho(result, "50-Hello ${'foo}"); + assertEcho(result, "51-Hello ${'foo}"); + assertEcho(result, "52-Hello #{'foo}"); + assertEcho(result, "53-Hello #{'foo}"); + } + + public void testBug48668b() throws Exception { + Tomcat tomcat = getTomcatInstance(); + + File appDir = new File("test/webapp-3.0"); + // app dir is relative to server home + tomcat.addWebapp(null, "/test", appDir.getAbsolutePath()); + + tomcat.start(); + + ByteChunk res = getUrl("http://localhost:" + getPort() + + "/test/bug48nnn/bug48668b.jsp"); + String result = res.toString(); + assertEcho(result, "00-Hello world</p>#{foo.bar}"); + assertEcho(result, "01-Hello world</p>#{foo2"); + } + + public void testBug49297NoSpaceNotStrict() throws Exception { + + Tomcat tomcat = getTomcatInstance(); + + File appDir = new File("test/webapp-3.0"); + // app dir is relative to server home + tomcat.addWebapp(null, "/test", appDir.getAbsolutePath()); + + tomcat.start(); + + ByteChunk res = new ByteChunk(); + int sc = getUrl("http://localhost:" + getPort() + + "/test/bug49297NoSpace.jsp", res, + new HashMap<String,List<String>>()); + + + assertEquals(200, sc); + assertEcho(res.toString(), "Hello World"); + } + + public void testBug49297DuplicateAttr() throws Exception { + Tomcat tomcat = getTomcatInstance(); + + File appDir = new File("test/webapp-3.0"); + // app dir is relative to server home + tomcat.addWebapp(null, "/test", appDir.getAbsolutePath()); + + tomcat.start(); + + int sc = getUrl("http://localhost:" + getPort() + + "/test/bug49297DuplicateAttr.jsp", new ByteChunk(), + new HashMap<String,List<String>>()); + + assertEquals(500, sc); + } + + /** Assertion for text printed by tags:echo */ + private static void assertEcho(String result, String expected) { + assertTrue(result.indexOf("<p>" + expected + "</p>") > 0); + } +} Propchange: tomcat/trunk/test/org/apache/jasper/compiler/TestParserNoStrictWhitespace.java ------------------------------------------------------------------------------ svn:eol-style = native Modified: tomcat/trunk/test/webapp-3.0/WEB-INF/tags/echo.tag URL: http://svn.apache.org/viewvc/tomcat/trunk/test/webapp-3.0/WEB-INF/tags/echo.tag?rev=1024229&r1=1024228&r2=1024229&view=diff ============================================================================== --- tomcat/trunk/test/webapp-3.0/WEB-INF/tags/echo.tag (original) +++ tomcat/trunk/test/webapp-3.0/WEB-INF/tags/echo.tag Tue Oct 19 13:21:05 2010 @@ -15,4 +15,5 @@ limitations under the License. --%><%@ tag %><%@ attribute name="echo" type="java.lang.String"%><%@ +attribute name="dummy" type="java.lang.String" required="false"%><%@ tag body-content="empty" %><p>${echo}</p> \ No newline at end of file Added: tomcat/trunk/test/webapp-3.0/bug49297DuplicateAttr.jsp URL: http://svn.apache.org/viewvc/tomcat/trunk/test/webapp-3.0/bug49297DuplicateAttr.jsp?rev=1024229&view=auto ============================================================================== --- tomcat/trunk/test/webapp-3.0/bug49297DuplicateAttr.jsp (added) +++ tomcat/trunk/test/webapp-3.0/bug49297DuplicateAttr.jsp Tue Oct 19 13:21:05 2010 @@ -0,0 +1,23 @@ +<%-- + 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. +--%> +<%@ taglib prefix="tags" tagdir="/WEB-INF/tags" %> +<html> + <head><title>Bug 49297 duplicate attribute test case</title></head> + <body> + <tags:echo echo="Hello World" echo="error"/> + </body> +</html> \ No newline at end of file Propchange: tomcat/trunk/test/webapp-3.0/bug49297DuplicateAttr.jsp ------------------------------------------------------------------------------ svn:eol-style = native Added: tomcat/trunk/test/webapp-3.0/bug49297NoSpace.jsp URL: http://svn.apache.org/viewvc/tomcat/trunk/test/webapp-3.0/bug49297NoSpace.jsp?rev=1024229&view=auto ============================================================================== --- tomcat/trunk/test/webapp-3.0/bug49297NoSpace.jsp (added) +++ tomcat/trunk/test/webapp-3.0/bug49297NoSpace.jsp Tue Oct 19 13:21:05 2010 @@ -0,0 +1,23 @@ +<%-- + 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. +--%> +<%@ taglib prefix="tags" tagdir="/WEB-INF/tags" %> +<html> + <head><title>Bug 49297 whitespace test case</title></head> + <body> + <tags:echo echo="Hello World"dummy="ignored"/> + </body> +</html> \ No newline at end of file Propchange: tomcat/trunk/test/webapp-3.0/bug49297NoSpace.jsp ------------------------------------------------------------------------------ svn:eol-style = native Modified: tomcat/trunk/webapps/docs/changelog.xml URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/changelog.xml?rev=1024229&r1=1024228&r2=1024229&view=diff ============================================================================== --- tomcat/trunk/webapps/docs/changelog.xml (original) +++ tomcat/trunk/webapps/docs/changelog.xml Tue Oct 19 13:21:05 2010 @@ -49,6 +49,15 @@ <subsection name="Jasper"> <changelog> <fix> + <bug>49297</bug>: Enforce the rules in the JSP specification for parsing + the attributes of custom and standard actions that require that + the attribute names are unique within an element and that there is + whitespace before the attribute name. The whitespace test can be + disabled by setting the system property + <code>org.apache.jasper.compiler.Parser.STRICT_WHITESPACE</code> to + <code>false</code>. (markt) + </fix> + <fix> <bug>50105</bug>: When processing composite EL expressions use <code>Enum.name()</code> rather than <code>Enum.toString()</code> as required by the EL specification. (markt) Modified: tomcat/trunk/webapps/docs/config/systemprops.xml URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/config/systemprops.xml?rev=1024229&r1=1024228&r2=1024229&view=diff ============================================================================== --- tomcat/trunk/webapps/docs/config/systemprops.xml (original) +++ tomcat/trunk/webapps/docs/config/systemprops.xml Tue Oct 19 13:21:05 2010 @@ -125,6 +125,13 @@ <code>true</code> will be used.</p> </property> + <property name="org.apache.jasper.compiler. Parser.STRICT_WHITESPACE"> + <p>If <code>false</code> the requirements for whitespace before an + attribute name will be relaxed so that the lack of whitespace will not + cause an error. If not specified, the specification compliant default of + <code>true</code> will be used.</p> + </property> + <property name="org.apache.jasper.runtime. BodyContentImpl.LIMIT_BUFFER"> <p>If <code>true</code>, any tag buffer that expands beyond <code>org.apache.jasper.Constants.DEFAULT_TAG_BUFFER_SIZE</code> will be --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org