Author: markt
Date: Mon Oct 27 06:17:35 2008
New Revision: 708165

URL: http://svn.apache.org/viewvc?rev=708165&view=rev
Log:
Various EL parsing fixes. Note: the behaviour regarding un-escaping of EL in 
attributes has been confirmed as correct with the EG.

Modified:
    tomcat/tc6.0.x/trunk/java/org/apache/jasper/Constants.java
    tomcat/tc6.0.x/trunk/java/org/apache/jasper/compiler/Compiler.java
    tomcat/tc6.0.x/trunk/java/org/apache/jasper/compiler/Generator.java
    tomcat/tc6.0.x/trunk/java/org/apache/jasper/compiler/JspDocumentParser.java
    tomcat/tc6.0.x/trunk/java/org/apache/jasper/compiler/Parser.java
    tomcat/tc6.0.x/trunk/java/org/apache/jasper/compiler/ParserController.java
    tomcat/tc6.0.x/trunk/java/org/apache/jasper/compiler/Validator.java

Modified: tomcat/tc6.0.x/trunk/java/org/apache/jasper/Constants.java
URL: 
http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/jasper/Constants.java?rev=708165&r1=708164&r2=708165&view=diff
==============================================================================
--- tomcat/tc6.0.x/trunk/java/org/apache/jasper/Constants.java (original)
+++ tomcat/tc6.0.x/trunk/java/org/apache/jasper/Constants.java Mon Oct 27 
06:17:35 2008
@@ -183,8 +183,12 @@
     /**
      * A replacement char for "\$".
      * XXX This is a hack to avoid changing EL interpreter to recognize "\$"
+     * @deprecated
      */
     public static final char ESC = '\u001b';
+    /**
+     * @deprecated
+     */
     public static final String ESCStr = "'\\u001b'";
 
     /**

Modified: tomcat/tc6.0.x/trunk/java/org/apache/jasper/compiler/Compiler.java
URL: 
http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/jasper/compiler/Compiler.java?rev=708165&r1=708164&r2=708165&view=diff
==============================================================================
--- tomcat/tc6.0.x/trunk/java/org/apache/jasper/compiler/Compiler.java 
(original)
+++ tomcat/tc6.0.x/trunk/java/org/apache/jasper/compiler/Compiler.java Mon Oct 
27 06:17:35 2008
@@ -145,8 +145,28 @@
 
         ServletWriter writer = null;
         try {
+            /*
+             * The setting of isELIgnored changes the behaviour of the parser
+             * in subtle ways. To add to the 'fun', isELIgnored can be set in
+             * any file that forms part of the translation unit so setting it
+             * in a file included towards the end of the translation unit can
+             * change how the parser should have behaved when parsing content
+             * up to the point where isELIgnored was set. Arghh!
+             * Previous attempts to hack around this have only provided partial
+             * solutions. We now use two passes to parse the translation unit.
+             * The first just parses the directives and the second parses the
+             * whole translation unit once we know how isELIgnored has been 
set.
+             * TODO There are some possible optimisations of this process.  
+             */ 
             // Parse the file
             ParserController parserCtl = new ParserController(ctxt, this);
+
+            // Pass 1 - the directives
+            Node.Nodes directives =
+                parserCtl.parseDirectives(ctxt.getJspFile());
+            Validator.validateDirectives(this, directives);
+
+            // Pass 2 - the whole translation unit
             pageNodes = parserCtl.parse(ctxt.getJspFile());
 
             if (ctxt.isPrototypeMode()) {
@@ -158,8 +178,9 @@
                 return null;
             }
 
-            // Validate and process attributes
-            Validator.validate(this, pageNodes);
+            // Validate and process attributes - don't re-validate the
+            // directives we validated in pass 1
+            Validator.validateExDirectives(this, pageNodes);
 
             if (log.isDebugEnabled()) {
                 t2 = System.currentTimeMillis();

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=708165&r1=708164&r2=708165&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 Mon Oct 
27 06:17:35 2008
@@ -806,13 +806,8 @@
                 }
                 return v;
             } else if (attr.isELInterpreterInput()) {
-                boolean replaceESC = v.indexOf(Constants.ESC) > 0;
-                v = JspUtil.interpreterCall(this.isTagFile, v, expectedType,
-                        attr.getEL().getMapName(), false);
-                // XXX ESC replacement hack
-                if (replaceESC) {
-                    v = "(" + v + ").replace(" + Constants.ESCStr + ", '$')";
-                }
+                v = attributeValueWithEL(this.isTagFile, v, expectedType,
+                        attr.getEL().getMapName());
                 if (encode) {
                     return 
"org.apache.jasper.runtime.JspRuntimeLibrary.URLEncode("
                             + v + ", request.getCharacterEncoding())";
@@ -829,6 +824,68 @@
             }
         }
 
+
+        /*
+         * When interpreting the EL attribute value, literals outside the EL
+         * must not be unescaped but the EL processor will unescape them.
+         * Therefore, make sure only the EL expressions are processed by the EL
+         * processor.
+         */
+        private String attributeValueWithEL(boolean isTag, String tx,
+                Class<?> expectedType, String mapName) {
+            if (tx==null) return null;
+            int size = tx.length();
+            StringBuffer output = new StringBuffer(size);
+            boolean el = false;
+            int i = 0;
+            int mark = 0;
+            char ch;
+            
+            while(i < size){
+                ch = tx.charAt(i);
+                
+                // Start of an EL expression
+                if (!el && i+1 < size && ch == '$' && tx.charAt(i+1)=='{') {
+                    if (mark < i) {
+                        if (output.length() > 0) {
+                            output.append(" + ");
+                        }
+                        output.append(quote(tx.substring(mark, i)));
+                    }
+                    mark = i;
+                    el = true;
+                    i += 2;
+                } else if (ch=='\\' && i+1 < size &&
+                        (tx.charAt(i+1)=='$' || tx.charAt(i+1)=='}')) { 
+                    // Skip an escaped $ or }
+                    i += 2;
+                } else if (el && ch=='}') {
+                    // End of an EL expression
+                    if (output.length() > 0) {
+                        output.append(" + ");
+                    }
+                    output.append(
+                            JspUtil.interpreterCall(isTag,
+                                    tx.substring(mark, i+1), expectedType,
+                                    mapName, false));
+                    mark = i + 1;
+                    el = false;
+                    ++i;
+                } else {
+                    // Nothing to see here - move to next character
+                    ++i;
+                }
+            }
+            if (!el && mark < i) {
+                if (output.length() > 0) {
+                    output.append(" + ");
+                }
+                output.append(quote(tx.substring(mark, i)));
+            }
+            return output.toString();
+        }
+
+
         /**
          * Prints the attribute value specified in the param action, in the 
form
          * of name=value string.
@@ -2838,16 +2895,10 @@
                     attrValue = sb.toString();
                 } else {
                     // run attrValue through the expression interpreter
-                    boolean replaceESC = attrValue.indexOf(Constants.ESC) > 0;
                     String mapName = (attr.getEL() != null) ? attr.getEL()
                             .getMapName() : null;
-                    attrValue = JspUtil.interpreterCall(this.isTagFile,
-                            attrValue, c[0], mapName, false);
-                    // XXX hack: Replace ESC with '$'
-                    if (replaceESC) {
-                        attrValue = "(" + attrValue + ").replace("
-                                + Constants.ESCStr + ", '$')";
-                    }
+                    attrValue = attributeValueWithEL(this.isTagFile,
+                            attrValue, c[0], mapName);
                 }
             } else {
                 attrValue = convertString(c[0], attrValue, localName,

Modified: 
tomcat/tc6.0.x/trunk/java/org/apache/jasper/compiler/JspDocumentParser.java
URL: 
http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/jasper/compiler/JspDocumentParser.java?rev=708165&r1=708164&r2=708165&view=diff
==============================================================================
--- tomcat/tc6.0.x/trunk/java/org/apache/jasper/compiler/JspDocumentParser.java 
(original)
+++ tomcat/tc6.0.x/trunk/java/org/apache/jasper/compiler/JspDocumentParser.java 
Mon Oct 27 06:17:35 2008
@@ -580,6 +580,9 @@
                         lastCh = ch;
                     }
                 } else if (lastCh == '\\' && (ch == '$' || ch == '#')) {
+                    if (pageInfo.isELIgnored()) {
+                        ttext.write('\\');
+                    }
                     ttext.write(ch);
                     ch = 0;  // Not start of EL anymore
                 } else {

Modified: tomcat/tc6.0.x/trunk/java/org/apache/jasper/compiler/Parser.java
URL: 
http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/jasper/compiler/Parser.java?rev=708165&r1=708164&r2=708165&view=diff
==============================================================================
--- tomcat/tc6.0.x/trunk/java/org/apache/jasper/compiler/Parser.java (original)
+++ tomcat/tc6.0.x/trunk/java/org/apache/jasper/compiler/Parser.java Mon Oct 27 
06:17:35 2008
@@ -27,7 +27,6 @@
 import javax.servlet.jsp.tagext.TagInfo;
 import javax.servlet.jsp.tagext.TagLibraryInfo;
 
-import org.apache.jasper.Constants;
 import org.apache.jasper.JasperException;
 import org.apache.jasper.JspCompilationContext;
 import org.xml.sax.Attributes;
@@ -286,12 +285,11 @@
             } else if (ch == '\\' && i + 1 < size) {
                 ch = tx.charAt(i + 1);
                 if (ch == '\\' || ch == '\"' || ch == '\'' || ch == '>') {
+                    // \ " and ' are always unescaped regardless of if they are
+                    // inside or outside of an EL expression. JSP.1.6 takes
+                    // precedence over JSP.1.3.10 (confirmed with EG).
                     buf.append(ch);
                     i += 2;
-                } else if (ch == '$') {
-                    // Replace "\$" with some special char. XXX hack!
-                    buf.append(Constants.ESC);
-                    i += 2;
                 } else {
                     buf.append('\\');
                     ++i;
@@ -1335,11 +1333,8 @@
                 }
                 char next = (char) reader.peekChar();
                 // Looking for \% or \$ or \#
-                // TODO: only recognize \$ or \# if isELIgnored is false, but 
since
-                // it can be set in a page directive, it cannot be determined
-                // here. Argh! (which is the way it should be since we 
shouldn't
-                // convolude multiple steps at once and create confusing 
parsers...)
-                if (next == '%' || next == '$' || next == '#') {
+                if (next == '%' || ((next == '$' || next == '#') &&
+                        !pageInfo.isELIgnored())) {
                     ch = reader.nextChar();
                 }
             }

Modified: 
tomcat/tc6.0.x/trunk/java/org/apache/jasper/compiler/ParserController.java
URL: 
http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/jasper/compiler/ParserController.java?rev=708165&r1=708164&r2=708165&view=diff
==============================================================================
--- tomcat/tc6.0.x/trunk/java/org/apache/jasper/compiler/ParserController.java 
(original)
+++ tomcat/tc6.0.x/trunk/java/org/apache/jasper/compiler/ParserController.java 
Mon Oct 27 06:17:35 2008
@@ -104,6 +104,24 @@
     }
 
     /**
+     * Parses the directives of a JSP page or tag file. This is invoked by the
+     * compiler.
+     *
+     * @param inFileName The path to the JSP page or tag file to be parsed.
+     */
+    public Node.Nodes parseDirectives(String inFileName)
+    throws FileNotFoundException, JasperException, IOException {
+        // If we're parsing a packaged tag file or a resource included by it
+        // (using an include directive), ctxt.getTagFileJar() returns the 
+        // JAR file from which to read the tag file or included resource,
+        // respectively.
+        isTagFile = ctxt.isTagFile();
+        directiveOnly = true;
+        return doParse(inFileName, null, ctxt.getTagFileJarUrl());
+    }
+
+
+    /**
      * Processes an include directive with the given path.
      *
      * @param inFileName The path to the resource to be included.

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=708165&r1=708164&r2=708165&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 Mon Oct 
27 06:17:35 2008
@@ -1337,7 +1337,6 @@
                         }
 
                     } else {
-                        value = value.replace(Constants.ESC, '$');
                         result = new Node.JspAttribute(tai, qName, uri,
                                 localName, value, false, null, dynamic);
                     }
@@ -1692,15 +1691,13 @@
         }
     }
 
-    public static void validate(Compiler compiler, Node.Nodes page)
+    public static void validateDirectives(Compiler compiler, Node.Nodes page)
             throws JasperException {
-
-        /*
-         * Visit the page/tag directives first, as they are global to the page
-         * and are position independent.
-         */
         page.visit(new DirectiveVisitor(compiler));
+    }
 
+    public static void validateExDirectives(Compiler compiler, Node.Nodes page)
+        throws JasperException {
         // Determine the default output content type
         PageInfo pageInfo = compiler.getPageInfo();
         String contentType = pageInfo.getContentType();



---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to