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("&lt;");
+                            pos = j + 1;
+                        } else if (c == '>') {
+                            if (j > pos) {
+                                sb.append(s, pos, j);
+                            }
+                            sb.append("&gt;");
+                            pos = j + 1;
+                        } else if (c == '\'') {
+                            if (j > pos) {
+                                sb.append(s, pos, j);
+                            }
+                            sb.append("&#039;"); // &apos;
+                            pos = j + 1;
+                        } else if (c == '&') {
+                            if (j > pos) {
+                                sb.append(s, pos, j);
+                            }
+                            sb.append("&amp;");
+                            pos = j + 1;
+                        } else if (c == '"') {
+                            if (j > pos) {
+                                sb.append(s, pos, j);
+                            }
+                            sb.append("&#034;"); // &quot;
+                            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("&lt;");
-            } else if (c == '>') {
-                sb.append("&gt;");
-            } else if (c == '\'') {
-                sb.append("&#039;"); // &apos;
-            } else if (c == '&') {
-                sb.append("&amp;");
-            } else if (c == '"') {
-                sb.append("&#034;"); // &quot;
-            } 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: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to