--- java/org/apache/jasper/compiler/Generator.java (revision 1578812) +++ java/org/apache/jasper/compiler/Generator.java (working copy) @@ -1839,7 +1839,7 @@ out.print(" + \"\\\""); } else { out.print(DOUBLE_QUOTE); - out.print(attrs.getValue(i).replace("\"", """)); + out.print(jspAttrs[i].getValue().replace("\"", """)); out.print(DOUBLE_QUOTE); } } --- java/org/apache/jasper/compiler/Validator.java (revision 1578812) +++ java/org/apache/jasper/compiler/Validator.java (working copy) @@ -1359,34 +1359,41 @@ result = new Node.JspAttribute(tai, qName, uri, localName, value.substring(3, value.length() - 2), true, null, dynamic); - } else if (pageInfo.isELIgnored()) { - result = new Node.JspAttribute(tai, qName, uri, localName, - value, false, null, dynamic); } else { - // The attribute can contain expressions but is not a - // scriptlet expression; thus, we want to run it through - // the expression interpreter + ELNode.Nodes el = null; + if (!pageInfo.isELIgnored()) { + // The attribute can contain expressions but is not a + // scriptlet expression; thus, we want to run it through + // the expression interpreter - // validate expression syntax if string contains - // expression(s) - ELNode.Nodes el = ELParser.parse(value, pageInfo - .isDeferredSyntaxAllowedAsLiteral()); + // validate expression syntax if string contains + // expression(s) + el = ELParser.parse(value, + pageInfo.isDeferredSyntaxAllowedAsLiteral()); - if (el.containsEL()) { + if (el.containsEL()) { + validateFunctions(el, n); + } else { + el = null; + } + } - validateFunctions(el, n); - - if (n.getRoot().isXmlSyntax()) { + if (n instanceof Node.UninterpretedTag && + n.getRoot().isXmlSyntax()) { + if (el != null) { // The non-EL elements need to be XML escaped XmlEscapeNonELVisitor v = new XmlEscapeNonELVisitor(); el.visit(v); - result = new Node.JspAttribute(tai, qName, uri, - localName, v.getText(), false, el, dynamic); + value = v.getText(); } else { - result = new Node.JspAttribute(tai, qName, uri, - localName, value, false, el, dynamic); + value = xmlEscape(value); } + } + result = new Node.JspAttribute(tai, qName, uri, localName, + value, false, el, dynamic); + + if (el != null) { ELContextImpl ctx = new ELContextImpl(expressionFactory); ctx.setFunctionMapper(getFunctionMapper(el)); @@ -1399,11 +1406,8 @@ "jsp.error.invalid.expression", value, e .toString()); } + } - } else { - result = new Node.JspAttribute(tai, qName, uri, - localName, value, false, null, dynamic); - } } } else { // Value is null. Check for any NamedAttribute subnodes --- test/org/apache/jasper/compiler/TestParser.java (revision 1578812) +++ test/org/apache/jasper/compiler/TestParser.java (working copy) @@ -14,7 +14,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.apache.jasper.compiler; import java.io.File; @@ -27,8 +26,11 @@ import org.junit.Assert; import org.junit.Test; +import org.apache.catalina.WebResourceRoot; +import org.apache.catalina.core.StandardContext; import org.apache.catalina.startup.Tomcat; import org.apache.catalina.startup.TomcatBaseTest; +import org.apache.catalina.webresources.StandardRoot; import org.apache.tomcat.util.buf.ByteChunk; /** @@ -328,18 +330,56 @@ String result = res.toString(); - Assert.assertTrue(result.contains(""1foo1"") || - result.contains(""1foo1"")); - Assert.assertTrue(result.contains(""2bar2"") || - result.contains(""2bar2"")); - Assert.assertTrue(result.contains(""3a&b3"") || - result.contains(""3a&b3"")); - Assert.assertTrue(result.contains(""4&4"") || - result.contains(""4&4"")); - Assert.assertTrue(result.contains(""5'5"") || - result.contains(""5'5"")); + Assert.assertTrue(result, + result.contains(""1foo1<&>"") + || result.contains(""1foo1<&>"")); + Assert.assertTrue(result, + result.contains(""2bar2<&>"") + || result.contains(""2bar2<&>"")); + Assert.assertTrue(result, + result.contains(""3a&b3"") + || result.contains(""3a&b3"")); + Assert.assertTrue(result, + result.contains(""4&4"") + || result.contains(""4&4"")); + Assert.assertTrue(result, + result.contains(""5'5"") + || result.contains(""5'5"")); } + @Test + public void testBug56265() throws Exception { + Tomcat tomcat = getTomcatInstance(); + + File appDir = new File("test/webapp"); + // app dir is relative to server home + StandardContext ctxt = (StandardContext) tomcat.addWebapp(null, + "/test", appDir.getAbsolutePath()); + + // This test needs the JSTL libraries + File lib = new File("webapps/examples/WEB-INF/lib"); + ctxt.setResources(new StandardRoot(ctxt)); + ctxt.getResources().createWebResourceSet( + WebResourceRoot.ResourceSetType.POST, "/WEB-INF/lib", + lib.getAbsolutePath(), null, "/"); + + tomcat.start(); + + ByteChunk res = getUrl("http://localhost:" + getPort() + + "/test/bug5nnnn/bug56265.jsp"); + + String result = res.toString(); + + Assert.assertTrue(result, + result.contains("[1: [data-test]: [window.alert('Hello World <&>!')]]")); + Assert.assertTrue(result, + result.contains("[2: [data-test]: [window.alert('Hello World <&>!')]]")); + Assert.assertTrue(result, + result.contains("[3: [data-test]: [window.alert('Hello 'World <&>'!')]]")); + Assert.assertTrue(result, + result.contains("[4: [data-test]: [window.alert('Hello 'World <&>'!')]]")); + } + /** Assertion for text printed by tags:echo */ private static void assertEcho(String result, String expected) { assertTrue(result.indexOf("

" + expected + "

") > 0); --- test/webapp/WEB-INF/tags/bug55198.tagx (revision 1578812) +++ test/webapp/WEB-INF/tags/bug55198.tagx (working copy) @@ -17,8 +17,8 @@ --> -foo -bar +foo +bar foo foo foo --- test/webapp/WEB-INF/tags/bug56265.tagx (revision 0) +++ test/webapp/WEB-INF/tags/bug56265.tagx (working copy) @@ -0,0 +1,24 @@ + + + + + + [${e.key}]: [${e.value}] + + --- test/webapp/bug5nnnn/bug56265.jsp (revision 0) +++ test/webapp/bug5nnnn/bug56265.jsp (working copy) @@ -0,0 +1,30 @@ +<%-- + 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" %> +<% +request.setAttribute("text", "World <&>"); +request.setAttribute("textQuote", "'World <&>'"); +%> + + Bug 56265 test case + +

[1: ]

+

[2: ]

+

[3: ]

+

[4: ]

+ +