Author: byron
Date: Wed Jan 21 08:36:34 2009
New Revision: 736335
URL: http://svn.apache.org/viewvc?rev=736335&view=rev
Log:
VELOCITY-623 Strict escaping behavior implementation
Added:
velocity/engine/trunk/src/test/org/apache/velocity/test/StrictEscapeTestCase.java
Modified:
velocity/engine/trunk/src/java/org/apache/velocity/runtime/RuntimeConstants.java
velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/Parser.java
velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/ParserTokenManager.java
velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/ASTReference.java
velocity/engine/trunk/src/parser/Parser.jjt
Modified:
velocity/engine/trunk/src/java/org/apache/velocity/runtime/RuntimeConstants.java
URL:
http://svn.apache.org/viewvc/velocity/engine/trunk/src/java/org/apache/velocity/runtime/RuntimeConstants.java?rev=736335&r1=736334&r2=736335&view=diff
==============================================================================
---
velocity/engine/trunk/src/java/org/apache/velocity/runtime/RuntimeConstants.java
(original)
+++
velocity/engine/trunk/src/java/org/apache/velocity/runtime/RuntimeConstants.java
Wed Jan 21 08:36:34 2009
@@ -59,6 +59,11 @@
String RUNTIME_REFERENCES_STRICT = "runtime.references.strict";
/**
+ * Indicates we are going to use modifed escape behavior in strict mode
+ */
+ String RUNTIME_REFERENCES_STRICT_ESCAPE =
"runtime.references.strict.escape";
+
+ /**
* @deprecated This appears to have always been meaningless.
*/
String RUNTIME_LOG_ERROR_STACKTRACE = "runtime.log.error.stacktrace";
Modified:
velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/Parser.java
URL:
http://svn.apache.org/viewvc/velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/Parser.java?rev=736335&r1=736334&r2=736335&view=diff
==============================================================================
---
velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/Parser.java
(original)
+++
velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/Parser.java
Wed Jan 21 08:36:34 2009
@@ -11,6 +11,7 @@
import org.apache.velocity.runtime.directive.MacroParseException;
import org.apache.velocity.util.StringUtils;
import org.apache.commons.lang.text.StrBuilder;
+import org.apache.velocity.runtime.RuntimeConstants;
/**
* This class is responsible for parsing a Velocity
@@ -28,7 +29,7 @@
*/
public class Parser/*...@bgen(jjtree)*/implements ParserTreeConstants,
ParserConstants {/*...@bgen(jjtree)*/
protected JJTParserState jjtree = new JJTParserState();/**
- * This Map contains a list of all of the dynamic directives.
+ * This Map contains a list of all of the dynamic directives.
*/
private Map directives = new HashMap();
@@ -38,10 +39,16 @@
private Map macroNames = new HashMap();
/**
- * Name of current template we are parsing. Passed to us in parse()
+ * Name of current template we are parsing. Passed to us in parse()
*/
public String currentTemplateName = "";
+ /**
+ * Set to true if the property
+ * RuntimeConstants.RUNTIME_REFERENCES_STRICT_ESCAPE is set to true
+ */
+ public boolean strictEscape = false;
+
VelocityCharStream velcharstream = null;
private RuntimeServices rsvc = null;
@@ -68,6 +75,10 @@
velcharstream = new VelocityCharStream(
new ByteArrayInputStream("\n".getBytes()), 1, 1 );
+
+ strictEscape =
+ rs.getBoolean(RuntimeConstants.RUNTIME_REFERENCES_STRICT_ESCAPE,
false);
+
/*
* and save the RuntimeServices
*/
@@ -187,14 +198,17 @@
}
/*
- * is this a PD or a control directive?
+ * If this is a predefined derective or if we detect
+ * a macro definition (this is aproximate at best) then
+ * we absorb the forward slash. If in strict reference
+ * mode then we always absord the forward slash regardless
+ * if the derective is defined or not.
*/
- if ( isDirective(dirTag) )
- {
- bRecognizedDirective = true;
- }
- else if (macroNames.containsKey(dirTag) || rsvc.isVelocimacro(dirTag,
currentTemplateName))
+ if (strictEscape
+ || isDirective(dirTag)
+ || macroNames.containsKey(dirTag)
+ || rsvc.isVelocimacro(dirTag, currentTemplateName))
{
bRecognizedDirective = true;
}
@@ -478,11 +492,13 @@
* if that failed, lets lookahead to see if we matched a PD or a VM
*/
String nTag = t.next.image.substring(1);
-
- if ( isDirective(nTag) )
- control = true;
- else if ( rsvc.isVelocimacro(nTag, currentTemplateName))
+ if (strictEscape
+ || isDirective(nTag)
+ || macroNames.containsKey(nTag)
+ || rsvc.isVelocimacro(nTag, currentTemplateName))
+ {
control = true;
+ }
jjtn000.val = "";
@@ -2769,108 +2785,6 @@
finally { jj_save(11, xla); }
}
- final private boolean jj_3_8() {
- if (jj_3R_33()) return true;
- return false;
- }
-
- final private boolean jj_3R_74() {
- if (jj_3R_73()) return true;
- return false;
- }
-
- final private boolean jj_3R_60() {
- if (jj_scan_token(IDENTIFIER)) return true;
- return false;
- }
-
- final private boolean jj_3R_97() {
- if (jj_scan_token(COMMA)) return true;
- if (jj_3R_29()) return true;
- return false;
- }
-
- final private boolean jj_3_12() {
- if (jj_scan_token(LBRACKET)) return true;
- Token xsp;
- xsp = jj_scanpos;
- if (jj_scan_token(31)) jj_scanpos = xsp;
- xsp = jj_scanpos;
- if (jj_3R_36()) {
- jj_scanpos = xsp;
- if (jj_3R_37()) return true;
- }
- xsp = jj_scanpos;
- if (jj_scan_token(31)) jj_scanpos = xsp;
- if (jj_scan_token(DOUBLEDOT)) return true;
- return false;
- }
-
- final private boolean jj_3R_71() {
- if (jj_scan_token(FALSE)) return true;
- return false;
- }
-
- final private boolean jj_3_4() {
- Token xsp;
- xsp = jj_scanpos;
- if (jj_scan_token(31)) jj_scanpos = xsp;
- xsp = jj_scanpos;
- if (jj_3R_27()) jj_scanpos = xsp;
- if (jj_3R_28()) return true;
- return false;
- }
-
- final private boolean jj_3R_63() {
- if (jj_3R_73()) return true;
- return false;
- }
-
- final private boolean jj_3R_88() {
- if (jj_scan_token(LPAREN)) return true;
- return false;
- }
-
- final private boolean jj_3R_30() {
- if (jj_3R_24()) return true;
- return false;
- }
-
- final private boolean jj_3R_87() {
- if (jj_3R_71()) return true;
- return false;
- }
-
- final private boolean jj_3R_70() {
- if (jj_scan_token(TRUE)) return true;
- return false;
- }
-
- final private boolean jj_3R_86() {
- if (jj_3R_70()) return true;
- return false;
- }
-
- final private boolean jj_3_9() {
- if (jj_scan_token(DOT)) return true;
- Token xsp;
- xsp = jj_scanpos;
- if (jj_3_10()) {
- jj_scanpos = xsp;
- if (jj_3R_34()) return true;
- }
- while (true) {
- xsp = jj_scanpos;
- if (jj_3R_90()) { jj_scanpos = xsp; break; }
- }
- return false;
- }
-
- final private boolean jj_3R_85() {
- if (jj_3R_69()) return true;
- return false;
- }
-
final private boolean jj_3R_84() {
if (jj_3R_68()) return true;
return false;
@@ -3192,11 +3106,6 @@
return false;
}
- final private boolean jj_3_2() {
- if (jj_scan_token(DOUBLE_ESCAPE)) return true;
- return false;
- }
-
final private boolean jj_3R_76() {
if (jj_3R_40()) return true;
return false;
@@ -3208,6 +3117,11 @@
return false;
}
+ final private boolean jj_3_2() {
+ if (jj_scan_token(DOUBLE_ESCAPE)) return true;
+ return false;
+ }
+
final private boolean jj_3R_91() {
Token xsp;
xsp = jj_scanpos;
@@ -3489,6 +3403,108 @@
return false;
}
+ final private boolean jj_3_8() {
+ if (jj_3R_33()) return true;
+ return false;
+ }
+
+ final private boolean jj_3R_74() {
+ if (jj_3R_73()) return true;
+ return false;
+ }
+
+ final private boolean jj_3R_60() {
+ if (jj_scan_token(IDENTIFIER)) return true;
+ return false;
+ }
+
+ final private boolean jj_3R_97() {
+ if (jj_scan_token(COMMA)) return true;
+ if (jj_3R_29()) return true;
+ return false;
+ }
+
+ final private boolean jj_3_12() {
+ if (jj_scan_token(LBRACKET)) return true;
+ Token xsp;
+ xsp = jj_scanpos;
+ if (jj_scan_token(31)) jj_scanpos = xsp;
+ xsp = jj_scanpos;
+ if (jj_3R_36()) {
+ jj_scanpos = xsp;
+ if (jj_3R_37()) return true;
+ }
+ xsp = jj_scanpos;
+ if (jj_scan_token(31)) jj_scanpos = xsp;
+ if (jj_scan_token(DOUBLEDOT)) return true;
+ return false;
+ }
+
+ final private boolean jj_3R_71() {
+ if (jj_scan_token(FALSE)) return true;
+ return false;
+ }
+
+ final private boolean jj_3_4() {
+ Token xsp;
+ xsp = jj_scanpos;
+ if (jj_scan_token(31)) jj_scanpos = xsp;
+ xsp = jj_scanpos;
+ if (jj_3R_27()) jj_scanpos = xsp;
+ if (jj_3R_28()) return true;
+ return false;
+ }
+
+ final private boolean jj_3R_63() {
+ if (jj_3R_73()) return true;
+ return false;
+ }
+
+ final private boolean jj_3R_88() {
+ if (jj_scan_token(LPAREN)) return true;
+ return false;
+ }
+
+ final private boolean jj_3R_30() {
+ if (jj_3R_24()) return true;
+ return false;
+ }
+
+ final private boolean jj_3R_87() {
+ if (jj_3R_71()) return true;
+ return false;
+ }
+
+ final private boolean jj_3R_70() {
+ if (jj_scan_token(TRUE)) return true;
+ return false;
+ }
+
+ final private boolean jj_3R_86() {
+ if (jj_3R_70()) return true;
+ return false;
+ }
+
+ final private boolean jj_3_9() {
+ if (jj_scan_token(DOT)) return true;
+ Token xsp;
+ xsp = jj_scanpos;
+ if (jj_3_10()) {
+ jj_scanpos = xsp;
+ if (jj_3R_34()) return true;
+ }
+ while (true) {
+ xsp = jj_scanpos;
+ if (jj_3R_90()) { jj_scanpos = xsp; break; }
+ }
+ return false;
+ }
+
+ final private boolean jj_3R_85() {
+ if (jj_3R_69()) return true;
+ return false;
+ }
+
public ParserTokenManager token_source;
public Token token, jj_nt;
private int jj_ntk;
Modified:
velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/ParserTokenManager.java
URL:
http://svn.apache.org/viewvc/velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/ParserTokenManager.java?rev=736335&r1=736334&r2=736335&view=diff
==============================================================================
---
velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/ParserTokenManager.java
(original)
+++
velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/ParserTokenManager.java
Wed Jan 21 08:36:34 2009
@@ -10,6 +10,7 @@
import org.apache.velocity.runtime.directive.MacroParseException;
import org.apache.velocity.util.StringUtils;
import org.apache.commons.lang.text.StrBuilder;
+import org.apache.velocity.runtime.RuntimeConstants;
public class ParserTokenManager implements ParserConstants
{
Modified:
velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/ASTReference.java
URL:
http://svn.apache.org/viewvc/velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/ASTReference.java?rev=736335&r1=736334&r2=736335&view=diff
==============================================================================
---
velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/ASTReference.java
(original)
+++
velocity/engine/trunk/src/java/org/apache/velocity/runtime/parser/node/ASTReference.java
Wed Jan 21 08:36:34 2009
@@ -83,6 +83,12 @@
*/
private ASTIndex astIndex = null;
+ /**
+ * Indicates if we are using modified escape behavior in strict mode.
+ * mainly we allow \$abc -> to render as $abc
+ */
+ public boolean strictEscape = false;
+
private int numChildren = 0;
protected Info uberInfo;
@@ -118,12 +124,11 @@
public Object init(InternalContextAdapter context, Object data)
throws TemplateInitException
{
- /*
- * init our children
- */
-
super.init(context, data);
-
+
+ strictEscape =
rsvc.getBoolean(RuntimeConstants.RUNTIME_REFERENCES_STRICT_ESCAPE, false);
+ strictRef =
rsvc.getBoolean(RuntimeConstants.RUNTIME_REFERENCES_STRICT, false);
+
/*
* the only thing we can do in init() is getRoot()
* as that is template based, not context based,
@@ -153,7 +158,6 @@
/*
* make an uberinfo - saves new's later on
*/
-
uberInfo = new Info(getTemplateName(), getLine(),getColumn());
/*
@@ -161,9 +165,7 @@
*/
logOnNull =
rsvc.getBoolean(RuntimeConstants.RUNTIME_LOG_REFERENCE_LOG_INVALID, true);
-
- strictRef =
rsvc.getBoolean(RuntimeConstants.RUNTIME_REFERENCES_STRICT, false);
-
+
/**
* In the case we are referencing a variable with #if($foo) or
* #if( ! $foo) then we allow variables to be undefined and we
@@ -340,7 +342,21 @@
return true;
}
- Object value = execute(null, context);
+ Object value = null;
+ if (escaped && strictEscape)
+ {
+ /**
+ * If we are in strict mode and the variable is escaped, then don't
bother to
+ * retreive the value since we won't use it. And if the var is not
defined
+ * it will throw an exception. Set value to TRUE to fall through
below with
+ * simply printing $foo, and not \$foo
+ */
+ value = Boolean.TRUE;
+ }
+ else
+ {
+ value = execute(null, context);
+ }
String localNullString = null;
@@ -395,7 +411,12 @@
* other...
*/
localNullString = getNullString(context);
- writer.write(escPrefix);
+ if (!strictEscape)
+ {
+ // If in strict escape mode then we only print escape once.
+ // Yea, I know.. brittle stuff
+ writer.write(escPrefix);
+ }
writer.write(escPrefix);
writer.write(morePrefix);
writer.write(localNullString);
@@ -710,6 +731,15 @@
if (slashbang != -1)
{
+ if (strictEscape)
+ {
+ // If we are in strict escape mode, then we consider this type
of
+ // pattern a non-reference, and we print it out as schmoo...
+ nullString = literal();
+ escaped = true;
+ return literal();
+ }
+
/*
* lets do all the work here. I would argue that if this occurrs,
* it's not a reference at all, so preceeding \ characters in
front
Modified: velocity/engine/trunk/src/parser/Parser.jjt
URL:
http://svn.apache.org/viewvc/velocity/engine/trunk/src/parser/Parser.jjt?rev=736335&r1=736334&r2=736335&view=diff
==============================================================================
--- velocity/engine/trunk/src/parser/Parser.jjt (original)
+++ velocity/engine/trunk/src/parser/Parser.jjt Wed Jan 21 08:36:34 2009
@@ -87,6 +87,7 @@
import org.apache.velocity.runtime.directive.MacroParseException;
import org.apache.velocity.util.StringUtils;
import org.apache.commons.lang.text.StrBuilder;
+import org.apache.velocity.runtime.RuntimeConstants;
/**
* This class is responsible for parsing a Velocity
@@ -105,7 +106,7 @@
public class Parser
{
/**
- * This Map contains a list of all of the dynamic directives.
+ * This Map contains a list of all of the dynamic directives.
*/
private Map directives = new HashMap();
@@ -115,10 +116,16 @@
private Map macroNames = new HashMap();
/**
- * Name of current template we are parsing. Passed to us in parse()
+ * Name of current template we are parsing. Passed to us in parse()
*/
public String currentTemplateName = "";
-
+
+ /**
+ * Set to true if the property
+ * RuntimeConstants.RUNTIME_REFERENCES_STRICT_ESCAPE is set to true
+ */
+ public boolean strictEscape = false;
+
VelocityCharStream velcharstream = null;
private RuntimeServices rsvc = null;
@@ -144,6 +151,10 @@
*/
velcharstream = new VelocityCharStream(
new ByteArrayInputStream("\n".getBytes()), 1, 1 );
+
+
+ strictEscape =
+ rs.getBoolean(RuntimeConstants.RUNTIME_REFERENCES_STRICT_ESCAPE,
false);
/*
* and save the RuntimeServices
@@ -264,14 +275,17 @@
}
/*
- * is this a PD or a control directive?
+ * If this is a predefined derective or if we detect
+ * a macro definition (this is aproximate at best) then
+ * we absorb the forward slash. If in strict reference
+ * mode then we always absord the forward slash regardless
+ * if the derective is defined or not.
*/
- if ( isDirective(dirTag) )
- {
- bRecognizedDirective = true;
- }
- else if (macroNames.containsKey(dirTag) || rsvc.isVelocimacro(dirTag,
currentTemplateName))
+ if (strictEscape
+ || isDirective(dirTag)
+ || macroNames.containsKey(dirTag)
+ || rsvc.isVelocimacro(dirTag, currentTemplateName))
{
bRecognizedDirective = true;
}
@@ -1296,11 +1310,13 @@
* if that failed, lets lookahead to see if we matched a PD or a VM
*/
String nTag = t.next.image.substring(1);
-
- if ( isDirective(nTag) )
- control = true;
- else if ( rsvc.isVelocimacro(nTag, currentTemplateName))
+ if (strictEscape
+ || isDirective(nTag)
+ || macroNames.containsKey(nTag)
+ || rsvc.isVelocimacro(nTag, currentTemplateName))
+ {
control = true;
+ }
jjtThis.val = "";
Added:
velocity/engine/trunk/src/test/org/apache/velocity/test/StrictEscapeTestCase.java
URL:
http://svn.apache.org/viewvc/velocity/engine/trunk/src/test/org/apache/velocity/test/StrictEscapeTestCase.java?rev=736335&view=auto
==============================================================================
---
velocity/engine/trunk/src/test/org/apache/velocity/test/StrictEscapeTestCase.java
(added)
+++
velocity/engine/trunk/src/test/org/apache/velocity/test/StrictEscapeTestCase.java
Wed Jan 21 08:36:34 2009
@@ -0,0 +1,93 @@
+package org.apache.velocity.test;
+/*
+ * 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.
+ */
+import org.apache.velocity.exception.MethodInvocationException;
+import org.apache.velocity.exception.ParseErrorException;
+import org.apache.velocity.runtime.RuntimeConstants;
+
+
+/**
+ * Test Strict escape mode
+ * property: RuntimeConstants.RUNTIME_REFERENCES_STRICT_ESCAPE set to true
+ */
+public class StrictEscapeTestCase extends BaseEvalTestCase
+{
+ public StrictEscapeTestCase(String name)
+ {
+ super(name);
+ }
+
+ public void setUp() throws Exception
+ {
+ super.setUp();
+ engine.setProperty(RuntimeConstants.RUNTIME_REFERENCES_STRICT_ESCAPE,
true);
+ context.put("pow", "bang");
+ }
+
+ /**
+ * Test that escaping works in strict mode
+ */
+ public void testVarEscape()
+ {
+ assertEvalEquals("\\$bogus", "\\\\$bogus");
+ assertEvalEquals("\\\\$bogus", "\\\\\\\\$bogus");
+ assertEvalEquals("\\$bogus", "#set($foo = \"\\\\$bogus\")$foo");
+
+ assertEvalEquals("$bogus", "\\$bogus");
+ assertEvalEquals("$bogus.xyz", "\\$bogus.xyz");
+ assertEvalEquals("${bogus}", "\\${bogus}");
+ assertEvalEquals("${bogus.xyz}", "\\${bogus.xyz}");
+ assertEvalEquals("\\$bogus", "\\\\\\$bogus");
+ assertEvalEquals("\\xyz","#set($foo = \"xyz\")\\\\$foo");
+ assertEvalEquals("\\$foo","#set($foo = \"xyz\")\\\\\\$foo");
+ assertEvalEquals("$foo\\","#set($foo = \"xyz\")\\$foo\\");
+ assertEvalEquals("$pow", "#set($foo = \"\\$pow\")$foo");
+ assertEvalEquals("\\bang", "#set($foo = \"\\\\$pow\")$foo");
+ assertEvalEquals("\\$pow", "#set($foo = \"\\\\\\$pow\")$foo");
+
+ assertEvalEquals("\\$%", "\\$%");
+ }
+
+
+ public void testMacroEscape()
+ {
+ assertEvalEquals("#bogus()", "\\#bogus()");
+ assertEvalEquals("\\#bogus", "\\\\#bogus");
+
+ // define the foo macro
+ assertEvalEquals("", "#macro(foo)bar#end");
+
+ assertEvalEquals("#foo()", "\\#foo()");
+ assertEvalEquals("\\bar", "\\\\#foo()");
+ assertEvalEquals("\\#foo()", "\\\\\\#foo()");
+
+ assertEvalEquals("bar", "#set($abc = \"#foo()\")$abc");
+ assertEvalEquals("#foo()", "#set($abc = \"\\#foo()\")$abc");
+ assertEvalEquals("\\bar", "#set($abc = \"\\\\#foo()\")$abc");
+
+ assertEvalEquals("#...@foo()", "\...@foo()");
+ assertEvalEquals("\\bar", "\\...@foo()#end");
+ assertEvalEquals("#...@foo()#end", "\...@foo()\\#end");
+
+ assertEvalEquals("#end #foreach #define() #elseif", "\\#end \\#foreach
\\#define() \\#elseif");
+ assertEvalEquals("#{end} #{foreach} #{define}() #{elseif}", "\\#{end}
\\#{foreach} \\#{define}() \\#{elseif}");
+ assertEvalEquals("#macro(foo) #end", "\\#macro(foo) \\#end");
+
+ }
+}