You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@struts.apache.org by lu...@apache.org on 2014/04/06 21:14:07 UTC

[05/31] git commit: Extends parser to allow parse collections

Extends parser to allow parse collections


Project: http://git-wip-us.apache.org/repos/asf/struts/repo
Commit: http://git-wip-us.apache.org/repos/asf/struts/commit/c03962c8
Tree: http://git-wip-us.apache.org/repos/asf/struts/tree/c03962c8
Diff: http://git-wip-us.apache.org/repos/asf/struts/diff/c03962c8

Branch: refs/heads/feature/use-js-to-support-multiple-buttons
Commit: c03962c8c0d972c7e17a9f6d247887754fbe7f3f
Parents: 49ecb5f
Author: Lukasz Lenart <lu...@apache.org>
Authored: Sat Mar 22 09:41:00 2014 +0100
Committer: Lukasz Lenart <lu...@apache.org>
Committed: Sat Mar 22 09:41:00 2014 +0100

----------------------------------------------------------------------
 .../opensymphony/xwork2/util/TextParseUtil.java | 87 ++++++++++++++++++++
 .../xwork2/util/TextParseUtilTest.java          | 45 +++++++++-
 2 files changed, 130 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/struts/blob/c03962c8/xwork-core/src/main/java/com/opensymphony/xwork2/util/TextParseUtil.java
----------------------------------------------------------------------
diff --git a/xwork-core/src/main/java/com/opensymphony/xwork2/util/TextParseUtil.java b/xwork-core/src/main/java/com/opensymphony/xwork2/util/TextParseUtil.java
index 4b54e81..a3938ef 100644
--- a/xwork-core/src/main/java/com/opensymphony/xwork2/util/TextParseUtil.java
+++ b/xwork-core/src/main/java/com/opensymphony/xwork2/util/TextParseUtil.java
@@ -16,9 +16,13 @@
 package com.opensymphony.xwork2.util;
 
 import com.opensymphony.xwork2.ActionContext;
+import com.opensymphony.xwork2.conversion.impl.XWorkConverter;
 import com.opensymphony.xwork2.inject.Container;
 
+import java.util.ArrayList;
+import java.util.Collection;
 import java.util.HashSet;
+import java.util.Map;
 import java.util.Set;
 
 
@@ -168,6 +172,89 @@ public class TextParseUtil {
     }
 
     /**
+     * @see #translateVariablesCollection(char[], String, ValueStack, boolean, ParsedValueEvaluator, int)
+     *
+     * @param expression
+     * @param stack
+     * @param excludeEmptyElements
+     * @param evaluator
+     * @return
+     */
+    public static Collection<String>  translateVariablesCollection(String expression, ValueStack stack, boolean excludeEmptyElements, ParsedValueEvaluator evaluator) {
+        return translateVariablesCollection(new char[]{'$', '%'}, expression, stack, excludeEmptyElements, evaluator, MAX_RECURSION);
+    }
+
+    /**
+     * Resolves given expression on given ValueStack. If found element is a
+     * collection each element will be converted to String. If just a single
+     * object is found it is converted to String and wrapped in a collection.
+     * 
+     * @param openChars
+     * @param expression
+     * @param stack
+     * @param excludeEmptyElements
+     * @param evaluator
+     * @param maxLoopCount
+     * @return
+     */
+    public static Collection<String> translateVariablesCollection(
+            char[] openChars, String expression, final ValueStack stack, boolean excludeEmptyElements,
+            final ParsedValueEvaluator evaluator, int maxLoopCount) {
+
+        ParsedValueEvaluator ognlEval = new ParsedValueEvaluator() {
+            public Object evaluate(String parsedValue) {
+                return stack.findValue(parsedValue); // no asType !!!
+            }
+        };
+
+        Map<String, Object> context = stack.getContext();
+        TextParser parser = ((Container)context.get(ActionContext.CONTAINER)).getInstance(TextParser.class);
+
+        Object result = parser.evaluate(openChars, expression, ognlEval, maxLoopCount);
+
+        XWorkConverter conv = ((Container)context.get(ActionContext.CONTAINER)).getInstance(XWorkConverter.class);
+
+        Collection<String> resultCol;
+        if (result instanceof Collection) {
+            @SuppressWarnings("unchecked")
+            Collection<Object> casted = (Collection<Object>)result;
+            resultCol = new ArrayList<String>(casted.size());
+            for (Object element : casted) {
+                String stringElement = (String)conv.convertValue(context, element, String.class);
+                if (shallBeIncluded(stringElement, excludeEmptyElements)) {
+                    if (evaluator != null) {
+                        stringElement = evaluator.evaluate(stringElement).toString();
+                    }
+                    resultCol.add(stringElement);
+                }
+            }
+        } else {
+            resultCol = new ArrayList<String>(1);
+            String stringResult = (String)conv.convertValue(context, result, String.class);
+            if (shallBeIncluded(stringResult, excludeEmptyElements)) {
+                if (evaluator != null) {
+                    stringResult = evaluator.evaluate(stringResult).toString();
+                }
+                resultCol.add(stringResult);
+            }
+        }
+
+        return resultCol;
+    }
+
+    /**
+     * Tests if given string is not null and not empty when excluding of empty
+     * elements is requested.
+     * 
+     * @param str String to check.
+     * @param excludeEmptyElements Whether empty elements shall be excluded.
+     * @return True if given string can be included in collection.
+     */
+    private static boolean shallBeIncluded(String str, boolean excludeEmptyElements) {
+        return !excludeEmptyElements || ((str != null) && (str.length() > 0));
+    }
+
+    /**
      * Returns a set from comma delimted Strings.
      * @param s The String to parse.
      * @return A set from comma delimted Strings.

http://git-wip-us.apache.org/repos/asf/struts/blob/c03962c8/xwork-core/src/test/java/com/opensymphony/xwork2/util/TextParseUtilTest.java
----------------------------------------------------------------------
diff --git a/xwork-core/src/test/java/com/opensymphony/xwork2/util/TextParseUtilTest.java b/xwork-core/src/test/java/com/opensymphony/xwork2/util/TextParseUtilTest.java
index 45e7970..a624a10 100644
--- a/xwork-core/src/test/java/com/opensymphony/xwork2/util/TextParseUtilTest.java
+++ b/xwork-core/src/test/java/com/opensymphony/xwork2/util/TextParseUtilTest.java
@@ -15,11 +15,19 @@
  */
 package com.opensymphony.xwork2.util;
 
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+
+import org.junit.Assert;
+
 import com.opensymphony.xwork2.ActionContext;
 import com.opensymphony.xwork2.XWorkTestCase;
 
-import java.util.*;
-
 /**
  * Unit test of {@link TextParseUtil}.
  *
@@ -177,4 +185,37 @@ public class TextParseUtilTest extends XWorkTestCase {
         assertEquals("foo: ", s);
     }
 
+    public void testTranslateVariablesCollection() {
+        ValueStack stack = ActionContext.getContext().getValueStack();
+        final List<String> list = new ArrayList<String>() {{
+            add("val 1");
+            add("val 2");
+        }};
+        stack.push(new HashMap<String, Object>() {{ put("list", list); }});
+
+        Collection<String> collection = TextParseUtil.translateVariablesCollection("${list}", stack, true, null);
+
+        Assert.assertNotNull(collection);
+        Assert.assertEquals(2, collection.size());
+    }
+
+    public void testTranslateVariablesCollectionWithExpressions() {
+        ValueStack stack = ActionContext.getContext().getValueStack();
+        final List<String> list = new ArrayList<String>() {{
+            add("${val1}");
+            add("%{val2}");
+        }};
+        stack.push(new HashMap<String, Object>() {{ put("list", list); put("val1", 1); put("val2", "Value 2"); }});
+
+        Collection<String> collection = TextParseUtil.translateVariablesCollection("${list}", stack, true, null);
+
+        Assert.assertNotNull(collection);
+        Assert.assertEquals(2, collection.size());
+
+        // if this starts passing, probably an double evaluation expression vulnerability was introduced
+        // carefully review changes as this can affect users and allows break in intruders
+        Assert.assertEquals("${val1}", collection.toArray()[0]);
+        Assert.assertEquals("%{val2}", collection.toArray()[1]);
+    }
+
 }