This is an automated email from the ASF dual-hosted git repository.

lukaszlenart pushed a commit to branch WW-3529-named-pattern
in repository https://gitbox.apache.org/repos/asf/struts.git

commit 993c4c4cab21ace8970d094da03291b21547ab83
Author: Lukasz Lenart <lukaszlen...@apache.org>
AuthorDate: Wed Oct 19 12:22:31 2022 +0200

    WW-3529 Fixes using RegEx related characters in named pattern
---
 .../xwork2/util/NamedVariablePatternMatcher.java   | 67 +++++++++++++---------
 .../util/NamedVariablePatternMatcherTest.java      | 27 +++++++--
 2 files changed, 61 insertions(+), 33 deletions(-)

diff --git 
a/core/src/main/java/com/opensymphony/xwork2/util/NamedVariablePatternMatcher.java
 
b/core/src/main/java/com/opensymphony/xwork2/util/NamedVariablePatternMatcher.java
index cb848868d..24e5e9b35 100644
--- 
a/core/src/main/java/com/opensymphony/xwork2/util/NamedVariablePatternMatcher.java
+++ 
b/core/src/main/java/com/opensymphony/xwork2/util/NamedVariablePatternMatcher.java
@@ -18,6 +18,8 @@
  */
 package com.opensymphony.xwork2.util;
 
+import org.apache.commons.lang3.StringUtils;
+
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
@@ -57,7 +59,7 @@ import java.util.regex.Pattern;
  * </table>
  *
  * <p>
- * Excaping hasn't been implemented since the intended use of these patterns 
will be in matching URLs.
+ * Escaping hasn't been implemented since the intended use of these patterns 
will be in matching URLs.
  * </p>
  *
  * @since 2.1
@@ -75,38 +77,47 @@ public class NamedVariablePatternMatcher implements 
PatternMatcher<NamedVariable
      * @return The compiled pattern, null if the pattern was null or empty
      */
     public CompiledPattern compilePattern(String data) {
+        if (StringUtils.isEmpty(data)) {
+            return null;
+        }
+
+        int len = data.length();
         StringBuilder regex = new StringBuilder();
-        if (data != null && data.length() > 0) {
-            List<String> varNames = new ArrayList<>();
-            StringBuilder varName = null;
-            for (int x=0; x<data.length(); x++) {
-                char c = data.charAt(x);
-                switch (c) {
-                    case '{' :  varName = new StringBuilder(); break;
-                    case '}' :  if (varName == null) {
-                                    throw new 
IllegalArgumentException("Mismatched braces in pattern");
-                                }
-                                varNames.add(varName.toString());
-                                regex.append("([^/]+)");
-                                varName = null;
-                                break;
-                    default  :  if (varName == null) {
-                                    regex.append(c);
-                                } else {
-                                    varName.append(c);
-                                }
-                }
+        List<String> varNames = new ArrayList<>();
+        int s = 0;
+        while (s < len) {
+            int e = data.indexOf('{', s);
+            if (e < 0 && data.indexOf('}') > -1) {
+                throw new IllegalArgumentException("Missing openning '{' in [" 
+ data + "]!");
+            }
+            if (e < 0) {
+                regex.append(Pattern.quote(data.substring(s)));
+                break;
+            }
+            if (e > s) {
+                regex.append(Pattern.quote(data.substring(s, e)));
+            }
+            s = e + 1;
+            e = data.indexOf('}', s);
+            if (e < 0) {
+                return null;
+            }
+            String varName = data.substring(s, e);
+            if (StringUtils.isEmpty(varName)) {
+                throw new IllegalArgumentException("Missing variable name in 
[" + data + "]!");
             }
-            return new CompiledPattern(Pattern.compile(regex.toString()), 
varNames);
+            varNames.add(varName);
+            regex.append("([^/]+)");
+            s = e + 1;
         }
-        return null;
+        return new CompiledPattern(Pattern.compile(regex.toString()), 
varNames);
     }
 
     /**
      * Tries to process the data against the compiled expression.  If 
successful, the map will contain
      * the matched data, using the specified variable names in the original 
pattern.
      *
-     * @param map The map of variables
+     * @param map  The map of variables
      * @param data The data to match
      * @param expr The compiled pattern
      * @return True if matched, false if not matched, the data was null, or 
the data was an empty string
@@ -116,8 +127,8 @@ public class NamedVariablePatternMatcher implements 
PatternMatcher<NamedVariable
         if (data != null && data.length() > 0) {
             Matcher matcher = expr.getPattern().matcher(data);
             if (matcher.matches()) {
-                for (int x=0; x<expr.getVariableNames().size(); x++)  {
-                    map.put(expr.getVariableNames().get(x), 
matcher.group(x+1));
+                for (int x = 0; x < expr.getVariableNames().size(); x++) {
+                    map.put(expr.getVariableNames().get(x), matcher.group(x + 
1));
                 }
                 return true;
             }
@@ -129,8 +140,8 @@ public class NamedVariablePatternMatcher implements 
PatternMatcher<NamedVariable
      * Stores the compiled pattern and the variable names matches will 
correspond to.
      */
     public static class CompiledPattern {
-        private Pattern pattern;
-        private List<String> variableNames;
+        private final Pattern pattern;
+        private final List<String> variableNames;
 
 
         public CompiledPattern(Pattern pattern, List<String> variableNames) {
diff --git 
a/core/src/test/java/com/opensymphony/xwork2/util/NamedVariablePatternMatcherTest.java
 
b/core/src/test/java/com/opensymphony/xwork2/util/NamedVariablePatternMatcherTest.java
index e11fb6870..b5eda4f0a 100644
--- 
a/core/src/test/java/com/opensymphony/xwork2/util/NamedVariablePatternMatcherTest.java
+++ 
b/core/src/test/java/com/opensymphony/xwork2/util/NamedVariablePatternMatcherTest.java
@@ -37,15 +37,18 @@ public class NamedVariablePatternMatcherTest {
         assertNull(matcher.compilePattern(null));
         assertNull(matcher.compilePattern(""));
 
-        CompiledPattern pattern = matcher.compilePattern("foo");
-        assertEquals("foo", pattern.getPattern().pattern());
+        CompiledPattern pattern = matcher.compilePattern("action.{format}");
+        assertEquals("\\Qaction.\\E([^/]+)", pattern.getPattern().pattern());
+
+        pattern = matcher.compilePattern("foo");
+        assertEquals("\\Qfoo\\E", pattern.getPattern().pattern());
 
         pattern = matcher.compilePattern("foo{jim}");
-        assertEquals("foo([^/]+)", pattern.getPattern().pattern());
+        assertEquals("\\Qfoo\\E([^/]+)", pattern.getPattern().pattern());
         assertEquals("jim", pattern.getVariableNames().get(0));
 
         pattern = matcher.compilePattern("foo{jim}/{bob}");
-        assertEquals("foo([^/]+)/([^/]+)", pattern.getPattern().pattern());
+        assertEquals("\\Qfoo\\E([^/]+)\\Q/\\E([^/]+)", 
pattern.getPattern().pattern());
         assertEquals("jim", pattern.getVariableNames().get(0));
         assertEquals("bob", pattern.getVariableNames().get(1));
         assertTrue(pattern.getPattern().matcher("foostar/jie").matches());
@@ -53,12 +56,26 @@ public class NamedVariablePatternMatcherTest {
     }
 
     @Test(expected = IllegalArgumentException.class)
-    public void testCompileWithMismatchedBracketsParses() {
+    public void testCompileWithMissingVariableName() {
+        NamedVariablePatternMatcher matcher = new 
NamedVariablePatternMatcher();
+
+        matcher.compilePattern("{}");
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testCompileWithMissingOpeningBracket1() {
         NamedVariablePatternMatcher matcher = new 
NamedVariablePatternMatcher();
 
         matcher.compilePattern("}");
     }
 
+    @Test(expected = IllegalArgumentException.class)
+    public void testCompileWithMissingOpeningBracket2() {
+        NamedVariablePatternMatcher matcher = new 
NamedVariablePatternMatcher();
+
+        matcher.compilePattern("test}");
+    }
+
     @Test
     public void testMatch() {
         NamedVariablePatternMatcher matcher = new 
NamedVariablePatternMatcher();

Reply via email to