Merge pull request #370 from apache/backport-regex-pattern-matcher

Add support for case-insensitive matching to RegExPatternMatcher
diff --git a/core/src/main/java/org/apache/shiro/util/RegExPatternMatcher.java b/core/src/main/java/org/apache/shiro/util/RegExPatternMatcher.java
index b251ac5..b07ce3d 100644
--- a/core/src/main/java/org/apache/shiro/util/RegExPatternMatcher.java
+++ b/core/src/main/java/org/apache/shiro/util/RegExPatternMatcher.java
@@ -29,12 +29,18 @@
  */
 public class RegExPatternMatcher implements PatternMatcher {
 
+    private static final int DEFAULT = Pattern.DOTALL;
+
+    private static final int CASE_INSENSITIVE = DEFAULT | Pattern.CASE_INSENSITIVE;
+
+    private boolean caseInsensitive = false;
+
     /**
      * Simple implementation that merely uses the default pattern comparison logic provided by the
      * JDK.
      * <p/>This implementation essentially executes the following:
      * <pre>
-     * Pattern p = Pattern.compile(pattern);
+     * Pattern p = Pattern.compile(pattern, Pattern.DOTALL);
      * Matcher m = p.matcher(source);
      * return m.matches();</pre>
      * @param pattern the pattern to match against
@@ -45,8 +51,24 @@
         if (pattern == null) {
             throw new IllegalArgumentException("pattern argument cannot be null.");
         }
-        Pattern p = Pattern.compile(pattern);
+        Pattern p = Pattern.compile(pattern, caseInsensitive ? CASE_INSENSITIVE : DEFAULT);
         Matcher m = p.matcher(source);
         return m.matches();
     }
+
+    /**
+     * Returns true if regex match should be case-insensitive.
+     * @return true if regex match should be case-insensitive.
+     */
+    public boolean isCaseInsensitive() {
+        return caseInsensitive;
+    }
+
+    /**
+     * Adds the Pattern.CASE_INSENSITIVE flag when compiling patterns.
+     * @param caseInsensitive true if patterns should match case-insensitive.
+     */
+    public void setCaseInsensitive(boolean caseInsensitive) {
+        this.caseInsensitive = caseInsensitive;
+    }
 }
diff --git a/core/src/test/java/org/apache/shiro/util/RegExPatternMatcherTest.java b/core/src/test/java/org/apache/shiro/util/RegExPatternMatcherTest.java
index 5246ba6..dc42368 100644
--- a/core/src/test/java/org/apache/shiro/util/RegExPatternMatcherTest.java
+++ b/core/src/test/java/org/apache/shiro/util/RegExPatternMatcherTest.java
@@ -21,8 +21,6 @@
 import org.junit.Test;
 import static org.junit.Assert.*;
 
-import java.util.regex.Pattern;
-
 /**
  * Unit tests for the {@link RegExPatternMatcher}.
  *
@@ -32,12 +30,44 @@
 
     @Test
     public void testSimplePattern() {
-        PatternMatcher pm = new RegExPatternMatcher();
-        String pattern = "a*b";
-        String test = "aaaaaaab";
-        //not necessary for the test, but Idea performs auto validation when it sees this:
-        Pattern.compile(pattern);
-        assertTrue(pm.matches(pattern, test));
+        assertPatternMatch("a*b", "aaaaaaab");
     }
 
+    @Test
+    public void testMatchesWithCarriageReturn() {
+        assertPatternMatch(".*", "/blah\n");
+    }
+
+    @Test
+    public void testMatchesWithLineFeed() {
+        assertPatternMatch(".*", "/blah\r");
+    }
+
+    @Test
+    public void testCaseInsensitive() {
+        RegExPatternMatcher pm = new RegExPatternMatcher();
+        pm.setCaseInsensitive(true);
+        assertPatternMatch("/blah", "/BlaH", pm);
+    }
+
+    @Test
+    public void testCaseSensitive() {
+        assertPatternNotMatch("/blah", "/BlaH");
+    }
+
+    private void assertPatternMatch(String pattern, String path) {
+        assertPatternMatch(pattern, path, new RegExPatternMatcher());
+    }
+
+    private void assertPatternMatch(String pattern, String path, PatternMatcher pm) {
+        assertTrue("Expected path '" + path + "' to match pattern '" + pattern + "'" , pm.matches(pattern, path));
+    }
+
+    private void assertPatternNotMatch(String pattern, String path) {
+        assertPatternNotMatch(pattern, path, new RegExPatternMatcher());
+    }
+
+    private void assertPatternNotMatch(String pattern, String path, PatternMatcher pm) {
+        assertFalse("Expected path '" + path + "' to NOT match pattern '" + pattern + "'" , pm.matches(pattern, path));
+    }
 }