Author: markt
Date: Wed Jan 8 13:22:40 2014
New Revision: 1556526
URL: http://svn.apache.org/r1556526
Log:
Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=55198
Correctly escape XML output from tagx files
Added:
tomcat/tc6.0.x/trunk/test/org/apache/jasper/compiler/TestELParser.java
(with props)
Modified:
tomcat/tc6.0.x/trunk/ (props changed)
tomcat/tc6.0.x/trunk/STATUS.txt
tomcat/tc6.0.x/trunk/java/org/apache/jasper/compiler/ELParser.java
tomcat/tc6.0.x/trunk/java/org/apache/jasper/compiler/Generator.java
tomcat/tc6.0.x/trunk/java/org/apache/jasper/compiler/Validator.java
tomcat/tc6.0.x/trunk/java/org/apache/jasper/runtime/PageContextImpl.java
tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml
Propchange: tomcat/tc6.0.x/trunk/
------------------------------------------------------------------------------
Merged /tomcat/trunk:r1500062,1539157,1539173
Merged /tomcat/tc7.0.x/trunk:r1500065,1539176-1539177
Modified: tomcat/tc6.0.x/trunk/STATUS.txt
URL:
http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/STATUS.txt?rev=1556526&r1=1556525&r2=1556526&view=diff
==============================================================================
--- tomcat/tc6.0.x/trunk/STATUS.txt (original)
+++ tomcat/tc6.0.x/trunk/STATUS.txt Wed Jan 8 13:22:40 2014
@@ -32,14 +32,6 @@ PATCHES PROPOSED TO BACKPORT:
[ New proposals should be added at the end of the list ]
-* Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=55198
- Correctly escape XML output from tagx files.
- http://svn.apache.org/r1500065 (excluding tests) - original fix
- http://svn.apache.org/r1539176 (excluding tests) - required for following fix
- http://svn.apache.org/r1539177 (excluding tests) - fixes regression in
original
- +1: markt, schultz, remm, jboynes
- -1:
-
* Fix issue with Manager app and other apps that use i18n in the UI when a
request that specifies an Accept-Language of English ahead of French, Spanish
or Japanese.
Modified: tomcat/tc6.0.x/trunk/java/org/apache/jasper/compiler/ELParser.java
URL:
http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/jasper/compiler/ELParser.java?rev=1556526&r1=1556525&r2=1556526&view=diff
==============================================================================
--- tomcat/tc6.0.x/trunk/java/org/apache/jasper/compiler/ELParser.java
(original)
+++ tomcat/tc6.0.x/trunk/java/org/apache/jasper/compiler/ELParser.java Wed Jan
8 13:22:40 2014
@@ -17,6 +17,12 @@
package org.apache.jasper.compiler;
+import org.apache.jasper.JasperException;
+import org.apache.jasper.compiler.ELNode.ELText;
+import org.apache.jasper.compiler.ELNode.Function;
+import org.apache.jasper.compiler.ELNode.Root;
+import org.apache.jasper.compiler.ELNode.Text;
+
/**
* This class implements a parser for EL expressions.
*
@@ -106,6 +112,7 @@ public class ELParser {
// Output whatever is in buffer
if (buf.length() > 0) {
ELexpr.add(new ELNode.ELText(buf.toString()));
+ buf = new StringBuffer();
}
if (!parseFunction()) {
ELexpr.add(new ELNode.ELText(curToken.toString()));
@@ -130,8 +137,8 @@ public class ELParser {
}
String s1 = null; // Function prefix
String s2 = curToken.toString(); // Function name
- int mark = getIndex();
if (hasNext()) {
+ int mark = getIndex();
Token t = nextToken();
if (t.toChar() == ':') {
if (hasNext()) {
@@ -149,8 +156,8 @@ public class ELParser {
ELexpr.add(new ELNode.Function(s1, s2));
return true;
}
+ setIndex(mark);
}
- setIndex(mark);
return false;
}
@@ -389,4 +396,42 @@ public class ELParser {
public char getType() {
return type;
}
+
+
+ protected static class TextBuilder extends ELNode.Visitor {
+
+ protected StringBuilder output = new StringBuilder();
+
+ public String getText() {
+ return output.toString();
+ }
+
+ @Override
+ public void visit(Root n) throws JasperException {
+ output.append(n.getType());
+ output.append('{');
+ n.getExpression().visit(this);
+ output.append('}');
+ }
+
+ @Override
+ public void visit(Function n) throws JasperException {
+ if (n.getPrefix() != null) {
+ output.append(n.getPrefix());
+ output.append(':');
+ }
+ output.append(n.getName());
+ output.append('(');
+ }
+
+ @Override
+ public void visit(Text n) throws JasperException {
+ output.append(n.getText());
+ }
+
+ @Override
+ public void visit(ELText n) throws JasperException {
+ output.append(n.getText());
+ }
+ }
}
Modified: tomcat/tc6.0.x/trunk/java/org/apache/jasper/compiler/Generator.java
URL:
http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/jasper/compiler/Generator.java?rev=1556526&r1=1556525&r2=1556526&view=diff
==============================================================================
--- tomcat/tc6.0.x/trunk/java/org/apache/jasper/compiler/Generator.java
(original)
+++ tomcat/tc6.0.x/trunk/java/org/apache/jasper/compiler/Generator.java Wed Jan
8 13:22:40 2014
@@ -818,7 +818,7 @@ class Generator {
* attributes that aren't EL expressions)
*/
private String attributeValue(Node.JspAttribute attr, boolean encode,
- Class expectedType) {
+ Class<?> expectedType, boolean isXml) {
String v = attr.getValue();
if (!attr.isNamedAttribute() && (v == null))
return "";
@@ -831,7 +831,7 @@ class Generator {
return v;
} else if (attr.isELInterpreterInput()) {
v = JspUtil.interpreterCall(this.isTagFile, v, expectedType,
- attr.getEL().getMapName(), false);
+ attr.getEL().getMapName(), isXml);
if (encode) {
return
"org.apache.jasper.runtime.JspRuntimeLibrary.URLEncode("
+ v + ", request.getCharacterEncoding())";
@@ -875,7 +875,8 @@ class Generator {
+ "URLEncode(" + quote(n.getTextAttribute("name"))
+ ", request.getCharacterEncoding())");
out.print("+ \"=\" + ");
- out.print(attributeValue(n.getValue(), true,
String.class));
+ out.print(attributeValue(n.getValue(), true, String.class,
+ n.getRoot().isXmlSyntax()));
// The separator is '&' after the second use
separator = "\"&\"";
@@ -941,7 +942,8 @@ class Generator {
pageParam = generateNamedAttributeValue(page
.getNamedAttributeNode());
} else {
- pageParam = attributeValue(page, false, String.class);
+ pageParam = attributeValue(page, false, String.class,
+ n.getRoot().isXmlSyntax());
}
// If any of the params have their values specified by
@@ -1027,7 +1029,8 @@ class Generator {
pageParam = generateNamedAttributeValue(page
.getNamedAttributeNode());
} else {
- pageParam = attributeValue(page, false, String.class);
+ pageParam = attributeValue(page, false, String.class,
+ n.getRoot().isXmlSyntax());
}
// If any of the params have their values specified by
@@ -1137,7 +1140,8 @@ class Generator {
+ "_jspx_page_context.findAttribute(\""
+ name
+ "\"), \"" + property + "\",");
- out.print(attributeValue(value, false, null));
+ out.print(attributeValue(value, false, null,
+ n.getRoot().isXmlSyntax()));
out.println(");");
} else if (value.isELInterpreterInput()) {
// We've got to resolve the very call to the interpreter
@@ -1185,7 +1189,8 @@ class Generator {
+ "_jspx_page_context.findAttribute(\""
+ name
+ "\"), \"" + property + "\", ");
- out.print(attributeValue(value, false, null));
+ out.print(attributeValue(value, false, null,
+ n.getRoot().isXmlSyntax()));
out.println(", null, null, false);");
}
@@ -1314,7 +1319,7 @@ class Generator {
.getNamedAttributeNode());
} else {
binaryName = attributeValue(beanName, false,
- String.class);
+ String.class, n.getRoot().isXmlSyntax());
}
} else {
// Implies klass is not null
@@ -1420,20 +1425,24 @@ class Generator {
// We want something of the form
// out.println( "<param name=\"blah\"
// value=\"" + ... + "\">" );
- out.printil("out.write( \"<param name=\\\""
- + escape(name)
- + "\\\" value=\\\"\" + "
- + attributeValue(n.getValue(), false,
- String.class) + " + \"\\\">\" );");
+ out.printil("out.write( \"<param name=\\\"" +
+ escape(name) +
+ "\\\" value=\\\"\" + " +
+ attributeValue(n.getValue(), false,
+ String.class,
+ n.getRoot().isXmlSyntax()) +
+ " + \"\\\">\" );");
out.printil("out.write(\"\\n\");");
} else {
// We want something of the form
// out.print( " blah=\"" + ... + "\"" );
- out.printil("out.write( \" "
- + escape(name)
- + "=\\\"\" + "
- + attributeValue(n.getValue(), false,
- String.class) + " + \"\\\"\" );");
+ out.printil("out.write( \" " +
+ escape(name) +
+ "=\\\"\" + " +
+ attributeValue(n.getValue(), false,
+ String.class,
+ n.getRoot().isXmlSyntax()) +
+ " + \"\\\"\" );");
}
n.setEndJavaLine(out.getJavaLine());
@@ -1460,7 +1469,8 @@ class Generator {
widthStr = generateNamedAttributeValue(width
.getNamedAttributeNode());
} else {
- widthStr = attributeValue(width, false, String.class);
+ widthStr = attributeValue(width, false, String.class,
+ n.getRoot().isXmlSyntax());
}
}
@@ -1470,7 +1480,8 @@ class Generator {
heightStr = generateNamedAttributeValue(height
.getNamedAttributeNode());
} else {
- heightStr = attributeValue(height, false, String.class);
+ heightStr = attributeValue(height, false, String.class,
+ n.getRoot().isXmlSyntax());
}
}
@@ -1822,7 +1833,8 @@ class Generator {
out.print("=");
if (jspAttrs[i].isELInterpreterInput()) {
out.print("\\\"\" + ");
- out.print(attributeValue(jspAttrs[i], false,
String.class));
+ out.print(attributeValue(jspAttrs[i], false, String.class,
+ n.getRoot().isXmlSyntax()));
out.print(" + \"\\\"");
} else {
out.print(DOUBLE_QUOTE);
@@ -1864,7 +1876,8 @@ class Generator {
attrStr = generateNamedAttributeValue(attrs[i]
.getNamedAttributeNode());
} else {
- attrStr = attributeValue(attrs[i], false, Object.class);
+ attrStr = attributeValue(attrs[i], false, Object.class,
+ n.getRoot().isXmlSyntax());
}
String s = " + \" " + attrs[i].getName() + "=\\\"\" + "
+ attrStr + " + \"\\\"\"";
@@ -1874,7 +1887,7 @@ class Generator {
// Write begin tag, using XML-style 'name' attribute as the
// element name
String elemName = attributeValue(n.getNameAttribute(), false,
- String.class);
+ String.class, n.getRoot().isXmlSyntax());
out.printin("out.write(\"<\"");
out.print(" + " + elemName);
Modified: tomcat/tc6.0.x/trunk/java/org/apache/jasper/compiler/Validator.java
URL:
http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/jasper/compiler/Validator.java?rev=1556526&r1=1556525&r2=1556526&view=diff
==============================================================================
--- tomcat/tc6.0.x/trunk/java/org/apache/jasper/compiler/Validator.java
(original)
+++ tomcat/tc6.0.x/trunk/java/org/apache/jasper/compiler/Validator.java Wed Jan
8 13:22:40 2014
@@ -38,6 +38,7 @@ import javax.servlet.jsp.tagext.Validati
import org.apache.el.lang.ELSupport;
import org.apache.jasper.JasperException;
+import org.apache.jasper.compiler.ELNode.Text;
import org.apache.jasper.el.ELContextImpl;
import org.xml.sax.Attributes;
@@ -1347,8 +1348,16 @@ class Validator {
validateFunctions(el, n);
- result = new Node.JspAttribute(tai, qName, uri,
- localName, value, false, el, dynamic);
+ if (n.getRoot().isXmlSyntax()) {
+ // 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);
+ } else {
+ result = new Node.JspAttribute(tai, qName, uri,
+ localName, value, false, el, dynamic);
+ }
ELContextImpl ctx = new ELContextImpl();
ctx.setFunctionMapper(getFunctionMapper(el));
@@ -1383,6 +1392,16 @@ class Validator {
return result;
}
+
+ private static class XmlEscapeNonELVisitor extends
ELParser.TextBuilder {
+
+ @Override
+ public void visit(Text n) throws JasperException {
+ output.append(xmlEscape(n.getText()));
+ }
+ }
+
+
/*
* Return an empty StringBuffer [not thread-safe]
*/
@@ -1823,4 +1842,67 @@ class Validator {
errDisp.jspError(errMsg.toString());
}
}
+
+ protected static String xmlEscape(String s) {
+ if (s == null) {
+ return null;
+ }
+ int len = s.length();
+
+ /*
+ * Look for any "bad" characters, Escape "bad" character was found
+ */
+ // ASCII " 34 & 38 ' 39 < 60 > 62
+ for (int i = 0; i < len; i++) {
+ char c = s.charAt(i);
+ if (c >= '\"' && c <= '>' &&
+ (c == '<' || c == '>' || c == '\'' || c == '&' || c ==
'"')) {
+ // need to escape them and then quote the whole string
+ StringBuilder sb = new StringBuilder((int) (len * 1.2));
+ sb.append(s, 0, i);
+ int pos = i + 1;
+ for (int j = i; j < len; j++) {
+ c = s.charAt(j);
+ if (c >= '\"' && c <= '>') {
+ if (c == '<') {
+ if (j > pos) {
+ sb.append(s, pos, j);
+ }
+ sb.append("<");
+ pos = j + 1;
+ } else if (c == '>') {
+ if (j > pos) {
+ sb.append(s, pos, j);
+ }
+ sb.append(">");
+ pos = j + 1;
+ } else if (c == '\'') {
+ if (j > pos) {
+ sb.append(s, pos, j);
+ }
+ sb.append("'"); // '
+ pos = j + 1;
+ } else if (c == '&') {
+ if (j > pos) {
+ sb.append(s, pos, j);
+ }
+ sb.append("&");
+ pos = j + 1;
+ } else if (c == '"') {
+ if (j > pos) {
+ sb.append(s, pos, j);
+ }
+ sb.append("""); // "
+ pos = j + 1;
+ }
+ }
+ }
+ if (pos < len) {
+ sb.append(s, pos, len);
+ }
+ return sb.toString();
+ }
+ }
+ return s;
+ }
}
Modified:
tomcat/tc6.0.x/trunk/java/org/apache/jasper/runtime/PageContextImpl.java
URL:
http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/jasper/runtime/PageContextImpl.java?rev=1556526&r1=1556525&r2=1556526&view=diff
==============================================================================
--- tomcat/tc6.0.x/trunk/java/org/apache/jasper/runtime/PageContextImpl.java
(original)
+++ tomcat/tc6.0.x/trunk/java/org/apache/jasper/runtime/PageContextImpl.java
Wed Jan 8 13:22:40 2014
@@ -866,28 +866,6 @@ public class PageContextImpl extends Pag
}
}
- private static String XmlEscape(String s) {
- if (s == null)
- return null;
- StringBuffer sb = new StringBuffer();
- for (int i = 0; i < s.length(); i++) {
- char c = s.charAt(i);
- if (c == '<') {
- sb.append("<");
- } else if (c == '>') {
- sb.append(">");
- } else if (c == '\'') {
- sb.append("'"); // '
- } else if (c == '&') {
- sb.append("&");
- } else if (c == '"') {
- sb.append("""); // "
- } else {
- sb.append(c);
- }
- }
- return sb.toString();
- }
/**
* Proprietary method to evaluate EL expressions. XXX - This method should
@@ -937,9 +915,6 @@ public class PageContextImpl extends Pag
ValueExpression ve = exprFactory.createValueExpression(ctx,
expression, expectedType);
retValue = ve.getValue(ctx);
}
- if (escape && retValue != null) {
- retValue = XmlEscape(retValue.toString());
- }
return retValue;
}
Added: tomcat/tc6.0.x/trunk/test/org/apache/jasper/compiler/TestELParser.java
URL:
http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/test/org/apache/jasper/compiler/TestELParser.java?rev=1556526&view=auto
==============================================================================
--- tomcat/tc6.0.x/trunk/test/org/apache/jasper/compiler/TestELParser.java
(added)
+++ tomcat/tc6.0.x/trunk/test/org/apache/jasper/compiler/TestELParser.java Wed
Jan 8 13:22:40 2014
@@ -0,0 +1,86 @@
+/*
+ * 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 org.apache.jasper.JasperException;
+import org.apache.jasper.compiler.ELNode.Nodes;
+import org.apache.jasper.compiler.ELParser.TextBuilder;
+
+import junit.framework.TestCase;
+
+public class TestELParser extends TestCase {
+
+ public void testText() throws JasperException {
+ doTestParser("foo");
+ }
+
+
+ public void testLiteral() throws JasperException {
+ doTestParser("${'foo'}");
+ }
+
+
+ public void testVariable() throws JasperException {
+ doTestParser("${test}");
+ }
+
+
+ public void testFunction01() throws JasperException {
+ doTestParser("${do(x)}");
+ }
+
+
+ public void testFunction02() throws JasperException {
+ doTestParser("${do:it(x)}");
+ }
+
+
+ public void testFunction03() throws JasperException {
+ doTestParser("${do:it(x,y)}");
+ }
+
+
+ public void testFunction04() throws JasperException {
+ doTestParser("${do:it(x,y,z)}");
+ }
+
+
+ public void testCompound01() throws JasperException {
+ doTestParser("1${'foo'}1");
+ }
+
+
+ public void testCompound02() throws JasperException {
+ doTestParser("1${test}1");
+ }
+
+
+ public void testCompound03() throws JasperException {
+ doTestParser("${foo}${bar}");
+ }
+
+
+ private void doTestParser(String input) throws JasperException {
+ Nodes nodes = ELParser.parse(input, false);
+
+ TextBuilder textBuilder = new TextBuilder();
+
+ nodes.visit(textBuilder);
+
+ assertEquals(input, textBuilder.getText());
+ }
+}
Propchange:
tomcat/tc6.0.x/trunk/test/org/apache/jasper/compiler/TestELParser.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml
URL:
http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml?rev=1556526&r1=1556525&r2=1556526&view=diff
==============================================================================
--- tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml (original)
+++ tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml Wed Jan 8 13:22:40 2014
@@ -107,6 +107,10 @@
<subsection name="Jasper">
<changelog>
<fix>
+ <bug>55198</bug>: Ensure attribute values in tagx files that include EL
+ and quoted XML characters are correctly quoted in the output. (markt)
+ </fix>
+ <fix>
<bug>55691</bug>: Fix <code>javax.el.ArrayELResolver</code> to
correctly
handle the case where the base object is an array of primitives.
(markt)
</fix>
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]