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]