commons-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From hen...@apache.org
Subject svn commit: r1147683 - in /commons/proper/jexl/trunk/src: main/java/org/apache/commons/jexl2/ test/java/org/apache/commons/jexl2/
Date Sun, 17 Jul 2011 17:20:32 GMT
Author: henrib
Date: Sun Jul 17 17:20:30 2011
New Revision: 1147683

URL: http://svn.apache.org/viewvc?rev=1147683&view=rev
Log:
JEXL-116: preamble to sandboxing
* Control over whether unknown variables, methods and constructors made independent from JexlArithmetic
leniency flag; JexlEngine thus regains a strict flag that controls this aspect of the behavior.
* Added ReadonlyContext that, as its name stand, will not allow  variables to be set or created.

Added:
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/ReadonlyContext.java
  (with props)
Modified:
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/Interpreter.java
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/JexlEngine.java
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/ObjectContext.java
    commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/UnifiedJEXL.java
    commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/VarTest.java

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/Interpreter.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/Interpreter.java?rev=1147683&r1=1147682&r2=1147683&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/Interpreter.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/Interpreter.java Sun
Jul 17 17:20:30 2011
@@ -106,7 +106,7 @@ public class Interpreter implements Pars
     /** Strict interpreter flag. */
     protected final boolean strict;
     /** Silent intepreter flag. */
-    protected boolean silent;
+    protected final boolean silent;
     /** Cache executors. */
     protected final boolean cache;
     /** Registers or arguments. */
@@ -122,14 +122,26 @@ public class Interpreter implements Pars
      * Creates an interpreter.
      * @param jexl the engine creating this interpreter
      * @param aContext the context to evaluate expression
+     * @deprecated 
      */
     public Interpreter(JexlEngine jexl, JexlContext aContext) {
+        this(jexl, aContext, !jexl.isLenient(), jexl.isSilent());
+    }
+    
+    /**
+     * Creates an interpreter.
+     * @param jexl the engine creating this interpreter
+     * @param aContext the context to evaluate expression
+     * @param strictFlag whether this interpreter runs in strict mode
+     * @param simentFlag whether this interpreter runs in silent mode
+     */
+    public Interpreter(JexlEngine jexl, JexlContext aContext, boolean strictFlag, boolean
silentFlag) {
         this.logger = jexl.logger;
         this.uberspect = jexl.uberspect;
         this.arithmetic = jexl.arithmetic;
         this.functions = jexl.functions;
-        this.strict = !this.arithmetic.isLenient();
-        this.silent = jexl.silent;
+        this.strict = strictFlag;
+        this.silent = silentFlag;
         this.cache = jexl.cache != null;
         this.context = aContext;
         this.functors = null;
@@ -152,16 +164,15 @@ public class Interpreter implements Pars
     }
 
     /**
-     * Sets whether this interpreter throws JexlException during evaluation.
-     * @param flag true means no JexlException will be thrown but will be logged
-     *        as info through the Jexl engine logger, false allows them to be thrown.
+     * Checks whether this interpreter considers unknown variables, methods and constructors
as errors.
+     * @return true if strict, false otherwise
      */
-    public void setSilent(boolean flag) {
-        this.silent = flag;
+    public boolean isStrict() {
+        return this.strict;
     }
-
+    
     /**
-     * Checks whether this interpreter throws JexlException during evaluation.
+     * Checks whether this interpreter throws JexlException when encountering errors.
      * @return true if silent, false otherwise
      */
     public boolean isSilent() {
@@ -249,7 +260,7 @@ public class Interpreter implements Pars
      */
     protected JexlNode findNullOperand(RuntimeException xrt, JexlNode node, Object left,
Object right) {
         if (xrt instanceof NullPointerException
-                && JexlException.NULL_OPERAND == xrt.getMessage()) {
+            && (Object) JexlException.NULL_OPERAND == xrt.getMessage()) {
             if (left == null) {
                 return node.jjtGetChild(0);
             }
@@ -555,7 +566,11 @@ public class Interpreter implements Pars
                     variableName.append(property);
                     property = variableName.toString();
                 }
-                context.set(String.valueOf(property), right);
+                try {
+                    context.set(String.valueOf(property), right);
+                } catch(UnsupportedOperationException xsupport) {
+                    throw new JexlException(node, "context is readonly", xsupport);
+                }
                 return right;
             }
         }
@@ -777,7 +792,8 @@ public class Interpreter implements Pars
             Object value = context.get(name);
             if (value == null
                     && !(node.jjtGetParent() instanceof ASTReference)
-                    && !context.has(name)) {
+                    && !context.has(name)
+                    && !isTernaryProtected(node)) {
                 JexlException xjexl = new JexlException(node, "undefined variable " + name);
                 return unknownVariable(xjexl);
             }

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/JexlEngine.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/JexlEngine.java?rev=1147683&r1=1147682&r2=1147683&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/JexlEngine.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/JexlEngine.java Sun Jul
17 17:20:30 2011
@@ -153,15 +153,19 @@ public class JexlEngine {
     protected final Parser parser = new Parser(new StringReader(";")); //$NON-NLS-1$
     /**
      * Whether expressions evaluated by this engine will throw exceptions (false) or 
-     * return null (true). Default is false.
+     * return null (true) on errors. Default is false.
      */
     protected boolean silent = false;
     /**
+     * Whether this engine is in lenient or strict mode; if unspecified, use the arithmetic
lenient property.
+     */
+    protected Boolean strict = null;
+    /**
      * Whether error messages will carry debugging information.
      */
     protected boolean debug = true;
     /**
-     *  The map of 'prefix:function' to object implementing the function.
+     *  The map of 'prefix:function' to object implementing the functions.
      */
     protected Map<String, Object> functions = Collections.emptyMap();
     /**
@@ -273,11 +277,12 @@ public class JexlEngine {
     }
 
     /**
-     * Sets whether this engine triggers errors during evaluation when null is used as
-     * an operand.
+     * Sets whether this engine considers unknown variables, methods and constructors as
errors or evaluates them
+     * as null.
      * <p>This method is <em>not</em> thread safe; it should be called
as an optional step of the JexlEngine
      * initialization code before expression creation &amp; evaluation.</p>
-     * <p>As of 2.0.2, you need a JexlThreadedArithmetic instance for this call to
succeed.</p>
+     * <p>As of 2.1, you need a JexlThreadedArithmetic instance for this call to also
modify the JexlArithmetic
+     * leniency behavior.</p>
      * @see JexlEngine#setSilent
      * @see JexlEngine#setDebug
      * @param flag true means no JexlException will occur, false allows them
@@ -285,19 +290,38 @@ public class JexlEngine {
     public void setLenient(boolean flag) {
         if (arithmetic instanceof JexlThreadedArithmetic) {
             JexlThreadedArithmetic.setLenient(Boolean.valueOf(flag));
-        } else if (flag != isLenient()) {
-            logger.warn("setLenient only has an effect when using a JexlThreadedArithmetic");
+        } else {
+            strict = flag? Boolean.FALSE : Boolean.TRUE;
         }
     }
 
     /**
-     * Checks whether this engine triggers errors during evaluation when null is used as
-     * an operand.
+     * Checks whether this engine considers unknown variables, methods and constructors as
errors.
+     * <p>If not explicitly set, the arithmetic leniency value applies.</p>
      * @return true if lenient, false if strict
      */
     public boolean isLenient() {
-        return this.arithmetic.isLenient();
+        return strict == null? arithmetic.isLenient() : !strict.booleanValue();
+    }
+        
+    /**
+     * Sets whether this engine behaves in strict or lenient mode.
+     * Equivalent to setLenient(!flag).
+     * @param flag true for strict, false for lenient
+     */
+    public final void setStrict(boolean flag) {
+        setLenient(!flag);
     }
+    
+    /**
+     * Checks whether this engine behaves in strict or lenient mode.
+     * Equivalent to !isLenient().
+     * @return true for strict, false for lenient
+     */
+    public final boolean isStrict() {
+        return !isLenient();
+    }
+
 
     /**
      * Sets the class loader used to discover classes in 'new' expressions.
@@ -730,10 +754,18 @@ public class JexlEngine {
      * @return an Interpreter
      */
     protected Interpreter createInterpreter(JexlContext context) {
-        if (context == null) {
-            context = EMPTY_CONTEXT;
-        }
-        return new Interpreter(this, context);
+        return createInterpreter(context, isStrict(), isSilent());
+    }
+    
+    /**
+     * Creates an interpreter.
+     * @param context a JexlContext; if null, the EMPTY_CONTEXT is used instead.
+     * @param strictFlag whether the interpreter runs in strict mode
+     * @param simentFlag whether the interpreter runs in silent mode
+     * @return an Interpreter
+     */
+    protected Interpreter createInterpreter(JexlContext context, boolean strictFlag, boolean
silentFlag) {
+        return new Interpreter(this, context == null? EMPTY_CONTEXT : context, strictFlag,
silentFlag);
     }
 
     /**

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/ObjectContext.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/ObjectContext.java?rev=1147683&r1=1147682&r2=1147683&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/ObjectContext.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/ObjectContext.java Sun
Jul 17 17:20:30 2011
@@ -14,12 +14,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package org.apache.commons.jexl2;
 
 /**
  * Wraps an Object as a Jexl context.
- * @param <T> the object type to use
+ * @param <T> the wrapped object type to use
  */
 public class ObjectContext<T> implements JexlContext {
     private final JexlEngine jexl;
@@ -39,10 +38,12 @@ public class ObjectContext<T> implements
     public Object get(String name) {
         return jexl.getProperty(object, name);
     }
+
     /** {@inheritDoc} */
     public void set(String name, Object value) {
         jexl.setProperty(object, name, value);
     }
+
     /** {@inheritDoc} */
     public boolean has(String name) {
         return jexl.getUberspect().getPropertyGet(object, name, null) != null;

Added: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/ReadonlyContext.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/ReadonlyContext.java?rev=1147683&view=auto
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/ReadonlyContext.java
(added)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/ReadonlyContext.java
Sun Jul 17 17:20:30 2011
@@ -0,0 +1,44 @@
+/*
+ * 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.commons.jexl2;
+
+/**
+ * A readonly context wrapper.
+ */
+public final class ReadonlyContext implements JexlContext {
+    /** The wrapped context. */
+    private final JexlContext base;
+
+    public ReadonlyContext(JexlContext theBase) {
+        base = theBase;
+    }
+
+    /** {@inheritDoc} */
+    public Object get(String name) {
+        return base.get(name);
+    }
+
+    /** {@inheritDoc} */
+    public void set(String name, Object value) {
+        throw new UnsupportedOperationException("Not supported.");
+    }
+
+    /** {@inheritDoc} */
+    public boolean has(String name) {
+        return base.has(name);
+    }
+}

Propchange: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/ReadonlyContext.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/UnifiedJEXL.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/UnifiedJEXL.java?rev=1147683&r1=1147682&r2=1147683&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/UnifiedJEXL.java (original)
+++ commons/proper/jexl/trunk/src/main/java/org/apache/commons/jexl2/UnifiedJEXL.java Sun
Jul 17 17:20:30 2011
@@ -76,9 +76,10 @@ public final class UnifiedJEXL {
     /** The JEXL engine instance. */
     private final JexlEngine jexl;
     /** The expression cache. */
-    private final JexlEngine.SoftCache<String,Expression> cache;
+    private final JexlEngine.SoftCache<String, Expression> cache;
     /** The default cache size. */
     private static final int CACHE_SIZE = 256;
+
     /**
      * Creates a new instance of UnifiedJEXL with a default size cache.
      * @param aJexl the JexlEngine to use.
@@ -94,7 +95,7 @@ public final class UnifiedJEXL {
      */
     public UnifiedJEXL(JexlEngine aJexl, int cacheSize) {
         this.jexl = aJexl;
-        this.cache = aJexl.new SoftCache<String,Expression>(cacheSize);
+        this.cache = aJexl.new SoftCache<String, Expression>(cacheSize);
     }
 
     /**
@@ -115,6 +116,7 @@ public final class UnifiedJEXL {
         COMPOSITE(-1);
         /** The index in arrays of expression counters for composite expressions. */
         private final int index;
+
         /**
          * Creates an ExpressionType.
          * @param idx the index for this type in counters arrays.
@@ -195,7 +197,7 @@ public final class UnifiedJEXL {
      * Clears the cache.
      */
     public void clearCache() {
-        synchronized(cache) {
+        synchronized (cache) {
             cache.clear();
         }
     }
@@ -206,6 +208,7 @@ public final class UnifiedJEXL {
     public static class Exception extends RuntimeException {
         /** Serial version UID. */
         private static final long serialVersionUID = -8201402995815975726L;
+
         /**
          * Creates a UnifiedJEXL.Exception.
          * @param msg the exception message
@@ -222,6 +225,7 @@ public final class UnifiedJEXL {
     public abstract class Expression {
         /** The source of this expression (see {@link UnifiedJEXL.Expression#prepare}). */
         protected final Expression source;
+
         /**
          * Creates an expression.
          * @param src the source expression if any
@@ -345,11 +349,11 @@ public final class UnifiedJEXL {
         abstract Object evaluate(Interpreter interpreter);
     }
 
-
     /** A constant expression. */
     private class ConstantExpression extends Expression {
         /** The constant held by this expression. */
         private final Object value;
+
         /**
          * Creates a constant expression.
          * <p>
@@ -428,13 +432,13 @@ public final class UnifiedJEXL {
         }
     }
 
-
     /** The base for Jexl based expressions. */
     private abstract class JexlBasedExpression extends Expression {
         /** The JEXL string for this expression. */
         protected final CharSequence expr;
         /** The JEXL node for this expression. */
         protected final JexlNode node;
+
         /**
          * Creates a JEXL interpretable expression.
          * @param theExpr the expression as a string
@@ -499,7 +503,6 @@ public final class UnifiedJEXL {
         }
     }
 
-
     /** An immediate expression: ${jexl}. */
     private class ImmediateExpression extends JexlBasedExpression {
         /**
@@ -591,7 +594,7 @@ public final class UnifiedJEXL {
         @Override
         public Expression prepare(Interpreter interpreter) {
             String value = interpreter.interpret(node).toString();
-            JexlNode dnode = toNode(value, jexl.isDebug()? node.getInfo() : null);
+            JexlNode dnode = toNode(value, jexl.isDebug() ? node.getInfo() : null);
             return new DeferredExpression(value, dnode, this);
         }
 
@@ -602,13 +605,13 @@ public final class UnifiedJEXL {
         }
     }
 
-
     /** A composite expression: "... ${...} ... #{...} ...". */
     private class CompositeExpression extends Expression {
         /** Bit encoded (deferred count > 0) bit 1, (immediate count > 0) bit 0. */
         private final int meta;
         /** The list of sub-expression resulting from parsing. */
         private final Expression[] exprs;
+
         /**
          * Creates a composite expression.
          * @param counters counters of expression per type
@@ -619,7 +622,7 @@ public final class UnifiedJEXL {
             super(src);
             this.exprs = list.toArray(new Expression[list.size()]);
             this.meta = (counters[ExpressionType.DEFERRED.index] > 0 ? 2 : 0)
-                      | (counters[ExpressionType.IMMEDIATE.index] > 0 ? 1 : 0);
+                    | (counters[ExpressionType.IMMEDIATE.index] > 0 ? 1 : 0);
         }
 
         /** {@inheritDoc} */
@@ -756,8 +759,10 @@ public final class UnifiedJEXL {
      */
     Expression prepare(JexlContext context, Expression expr) {
         try {
-            Interpreter interpreter = jexl.createInterpreter(context);
-            interpreter.setSilent(false);
+            if (context == null) {
+                context = JexlEngine.EMPTY_CONTEXT;
+            }
+            Interpreter interpreter = new Interpreter(jexl, context, !jexl.isLenient(), false);
             return expr.prepare(interpreter);
         } catch (JexlException xjexl) {
             Exception xuel = createException("prepare", expr, xjexl);
@@ -779,8 +784,7 @@ public final class UnifiedJEXL {
      */
     Object evaluate(JexlContext context, Expression expr) {
         try {
-            Interpreter interpreter = jexl.createInterpreter(context);
-            interpreter.setSilent(false);
+            Interpreter interpreter = jexl.createInterpreter(context, !jexl.isLenient(),
false);
             return expr.evaluate(interpreter);
         } catch (JexlException xjexl) {
             Exception xuel = createException("evaluate", expr, xjexl);
@@ -801,7 +805,7 @@ public final class UnifiedJEXL {
     private JexlNode toNode(CharSequence expression) {
         return jexl.parse(expression, null);
     }
-    
+
     /**
      * Use the JEXL parser to create the AST for an expression.
      * @param expression the expression to parse
@@ -837,7 +841,6 @@ public final class UnifiedJEXL {
         return new Exception(strb.toString(), xany);
     }
 
-
     /** The different parsing states. */
     private static enum ParseState {
         /** Parsing a constant. */

Modified: commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/VarTest.java
URL: http://svn.apache.org/viewvc/commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/VarTest.java?rev=1147683&r1=1147682&r2=1147683&view=diff
==============================================================================
--- commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/VarTest.java (original)
+++ commons/proper/jexl/trunk/src/test/java/org/apache/commons/jexl2/VarTest.java Sun Jul
17 17:20:30 2011
@@ -31,6 +31,37 @@ public class VarTest extends JexlTestCas
     public VarTest(String testName) {
         super(testName);
     }
+    
+    public void testStrict() throws Exception {
+        JexlContext map = new MapContext();
+        JexlContext ctxt = new ReadonlyContext(new MapContext());
+        JEXL.setStrict(true);
+        Script e;
+        
+        e = JEXL.createScript("x");
+        try {
+            Object o = e.execute(ctxt);
+            fail("should have thrown an unknown var exception");
+        } catch(JexlException xjexl) {
+            // ok since we are strict and x does not exist
+        } 
+        e = JEXL.createScript("x = 42");
+        try {
+            Object o = e.execute(ctxt);
+            fail("should have thrown a readonly context exception");
+        } catch(JexlException xjexl) {
+            // ok since we are strict and context is readonly
+        }   
+        
+        map.set("x", "fourty-two");
+        e = JEXL.createScript("x.theAnswerToEverything()");
+        try {
+            Object o = e.execute(ctxt);
+            fail("should have thrown an unknown method exception");
+        } catch(JexlException xjexl) {
+            // ok since we are strict and method does not exist
+        } 
+    }
 
     public void testLocalBasic() throws Exception {
         Script e = JEXL.createScript("var x; x = 42");



Mime
View raw message