Merge pull request #225 from bmhm/SHIRO-766

[SHIRO-766] ignore exception on invalid cookies.
diff --git a/.asf.yaml b/.asf.yaml
new file mode 100644
index 0000000..911d163
--- /dev/null
+++ b/.asf.yaml
@@ -0,0 +1,19 @@
+#
+# 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.
+#
+
+notifications:
+  pullrequests: commits@shiro.apache.org
diff --git a/all/pom.xml b/all/pom.xml
index 1241a05..19c348f 100644
--- a/all/pom.xml
+++ b/all/pom.xml
@@ -22,7 +22,7 @@
     <parent>
         <groupId>org.apache.shiro</groupId>
         <artifactId>shiro-root</artifactId>
-        <version>1.5.3-SNAPSHOT</version>
+        <version>2.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 
diff --git a/cache/pom.xml b/cache/pom.xml
index 87129ea..bed6d4e 100644
--- a/cache/pom.xml
+++ b/cache/pom.xml
@@ -22,7 +22,7 @@
     <parent>
         <groupId>org.apache.shiro</groupId>
         <artifactId>shiro-root</artifactId>
-        <version>1.5.3-SNAPSHOT</version>
+        <version>2.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 
diff --git a/config/core/pom.xml b/config/core/pom.xml
index 49ee920..faa8716 100644
--- a/config/core/pom.xml
+++ b/config/core/pom.xml
@@ -22,7 +22,7 @@
     <parent>
         <groupId>org.apache.shiro</groupId>
         <artifactId>shiro-config</artifactId>
-        <version>1.5.3-SNAPSHOT</version>
+        <version>2.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 
diff --git a/config/core/src/main/java/org/apache/shiro/config/Ini.java b/config/core/src/main/java/org/apache/shiro/config/Ini.java
index 1c42f0e..7993619 100644
--- a/config/core/src/main/java/org/apache/shiro/config/Ini.java
+++ b/config/core/src/main/java/org/apache/shiro/config/Ini.java
@@ -587,7 +587,7 @@
                 } else {
                     if (valueBuffer.length() == 0 && isKeyValueSeparatorChar(c) && !isCharEscaped(line, i)) {
                         //swallow the separator chars before we start building the value
-                    } else if (!isCharEscaped(line, i)){
+                    } else {
                         valueBuffer.append(c);
                     }
                 }
diff --git a/config/core/src/test/groovy/org/apache/shiro/config/IniTest.groovy b/config/core/src/test/groovy/org/apache/shiro/config/IniTest.groovy
index 56bb99e..cf9ee12 100644
--- a/config/core/src/test/groovy/org/apache/shiro/config/IniTest.groovy
+++ b/config/core/src/test/groovy/org/apache/shiro/config/IniTest.groovy
@@ -73,6 +73,22 @@
     }
 
     @Test
+    public void testBackslash() {
+        String test = "Truth=Beauty\\\\";
+        Ini ini = new Ini();
+        ini.load(test);
+
+        assertNotNull(ini.getSections());
+        assertEquals(1, ini.getSections().size());
+
+        Ini.Section section = ini.getSections().iterator().next();
+        assertEquals(Ini.DEFAULT_SECTION_NAME, section.getName());
+        assertFalse(section.isEmpty());
+        assertEquals(1, section.size());
+        assertEquals("Beauty\\\\", section.get("Truth"));
+    }
+
+    @Test
     public void testSplitKeyValue() {
         String test = "Truth Beauty";
         String[] kv = Ini.Section.splitKeyValue(test);
@@ -119,24 +135,40 @@
         assertEquals("Truth", kv[0]);
         assertEquals("Beauty", kv[1]);
 
+        // Escape characters are to be removed from the key.
+        // This is different behaviour compared to the XML config.
         test = "Tru\\th=Beauty";
         kv = Ini.Section.splitKeyValue(test);
         assertEquals("Truth", kv[0]);
         assertEquals("Beauty", kv[1]);
 
-        test = "Truth\\=Beauty";
-        kv = Ini.Section.splitKeyValue(test);
-        assertEquals("Truth", kv[0]);
-        assertEquals("Beauty", kv[1]);
-
+        // SHIRO-530: Keep backslashes in value.
         test = "Truth=Beau\\ty";
         kv = Ini.Section.splitKeyValue(test);
         assertEquals("Truth", kv[0]);
-        assertEquals("Beauty", kv[1]);
+        assertEquals("Beau\\ty", kv[1]);
 
+        // SHIRO-530: Keep backslashes in value.
         test = "Truth=Beauty\\";
         kv = Ini.Section.splitKeyValue(test);
         assertEquals("Truth", kv[0]);
+        assertEquals("Beauty\\", kv[1]);
+
+        // SHIRO-530: Keep backslashes in value.
+        test = "Truth= \\ Beauty\\";
+        kv = Ini.Section.splitKeyValue(test);
+        assertEquals("Truth", kv[0]);
+        assertEquals("\\ Beauty\\", kv[1]);
+    }
+
+    /**
+     * Tests if an escaped separator char will not be recognized as such.
+     */
+    @Test
+    public void testSplitKeyValueEscapedEquals()  {
+        String test = "Truth\\=Beauty";
+        String[] kv = Ini.Section.splitKeyValue(test);
+        assertEquals("Truth", kv[0]);
         assertEquals("Beauty", kv[1]);
     }
 
diff --git a/config/ogdl/pom.xml b/config/ogdl/pom.xml
index 98669c8..aa05dff 100644
--- a/config/ogdl/pom.xml
+++ b/config/ogdl/pom.xml
@@ -22,7 +22,7 @@
     <parent>
         <groupId>org.apache.shiro</groupId>
         <artifactId>shiro-config</artifactId>
-        <version>1.5.3-SNAPSHOT</version>
+        <version>2.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 
diff --git a/config/pom.xml b/config/pom.xml
index 4a8d552..0d39970 100644
--- a/config/pom.xml
+++ b/config/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.shiro</groupId>
         <artifactId>shiro-root</artifactId>
-        <version>1.5.3-SNAPSHOT</version>
+        <version>2.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 
diff --git a/core/pom.xml b/core/pom.xml
index 9075fa7..bf3ac48 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -22,7 +22,7 @@
     <parent>
         <groupId>org.apache.shiro</groupId>
         <artifactId>shiro-root</artifactId>
-        <version>1.5.3-SNAPSHOT</version>
+        <version>2.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 
diff --git a/core/src/main/java/org/apache/shiro/SecurityUtils.java b/core/src/main/java/org/apache/shiro/SecurityUtils.java
index d78ab07..058ccf4 100644
--- a/core/src/main/java/org/apache/shiro/SecurityUtils.java
+++ b/core/src/main/java/org/apache/shiro/SecurityUtils.java
@@ -34,7 +34,7 @@
      * ONLY used as a 'backup' in VM Singleton environments (that is, standalone environments), since the
      * ThreadContext should always be the primary source for Subject instances when possible.
      */
-    private static SecurityManager securityManager;
+    private static volatile SecurityManager securityManager;
 
     /**
      * Returns the currently accessible {@code Subject} available to the calling code depending on
diff --git a/crypto/cipher/pom.xml b/crypto/cipher/pom.xml
index 170d6bb..559624b 100644
--- a/crypto/cipher/pom.xml
+++ b/crypto/cipher/pom.xml
@@ -22,7 +22,7 @@
     <parent>
         <groupId>org.apache.shiro</groupId>
         <artifactId>shiro-crypto</artifactId>
-        <version>1.5.3-SNAPSHOT</version>
+        <version>2.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 
diff --git a/crypto/core/pom.xml b/crypto/core/pom.xml
index ef6f718..7297b58 100644
--- a/crypto/core/pom.xml
+++ b/crypto/core/pom.xml
@@ -22,7 +22,7 @@
     <parent>
         <groupId>org.apache.shiro</groupId>
         <artifactId>shiro-crypto</artifactId>
-        <version>1.5.3-SNAPSHOT</version>
+        <version>2.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 
diff --git a/crypto/hash/pom.xml b/crypto/hash/pom.xml
index 6e7d86f..17b9deb 100644
--- a/crypto/hash/pom.xml
+++ b/crypto/hash/pom.xml
@@ -22,7 +22,7 @@
     <parent>
         <groupId>org.apache.shiro</groupId>
         <artifactId>shiro-crypto</artifactId>
-        <version>1.5.3-SNAPSHOT</version>
+        <version>2.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 
diff --git a/crypto/pom.xml b/crypto/pom.xml
index 7ce8c44..b7f0e68 100644
--- a/crypto/pom.xml
+++ b/crypto/pom.xml
@@ -24,7 +24,7 @@
     <parent>
         <groupId>org.apache.shiro</groupId>
         <artifactId>shiro-root</artifactId>
-        <version>1.5.3-SNAPSHOT</version>
+        <version>2.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 
diff --git a/event/pom.xml b/event/pom.xml
index 6d6097b..19e8912 100644
--- a/event/pom.xml
+++ b/event/pom.xml
@@ -22,7 +22,7 @@
     <parent>
         <groupId>org.apache.shiro</groupId>
         <artifactId>shiro-root</artifactId>
-        <version>1.5.3-SNAPSHOT</version>
+        <version>2.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 
diff --git a/integration-tests/guice3/pom.xml b/integration-tests/guice3/pom.xml
index 9631b4b..37326b4 100644
--- a/integration-tests/guice3/pom.xml
+++ b/integration-tests/guice3/pom.xml
@@ -23,7 +23,7 @@
 	<parent>
 		<groupId>org.apache.shiro.integrationtests</groupId>
 		<artifactId>shiro-integration-tests</artifactId>
-		<version>1.5.3-SNAPSHOT</version>
+		<version>2.0.0-SNAPSHOT</version>
 		<relativePath>../pom.xml</relativePath>
 	</parent>
 
diff --git a/integration-tests/guice4/pom.xml b/integration-tests/guice4/pom.xml
index e066b35..37f45ca 100644
--- a/integration-tests/guice4/pom.xml
+++ b/integration-tests/guice4/pom.xml
@@ -23,7 +23,7 @@
 	<parent>
 		<groupId>org.apache.shiro.integrationtests</groupId>
 		<artifactId>shiro-integration-tests</artifactId>
-		<version>1.5.3-SNAPSHOT</version>
+		<version>2.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
 	</parent>
 
diff --git a/integration-tests/pom.xml b/integration-tests/pom.xml
index 0ffc1a2..6f4a8fb 100644
--- a/integration-tests/pom.xml
+++ b/integration-tests/pom.xml
@@ -23,7 +23,7 @@
     <parent>
         <groupId>org.apache.shiro</groupId>
         <artifactId>shiro-root</artifactId>
-        <version>1.5.3-SNAPSHOT</version>
+        <version>2.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 
diff --git a/integration-tests/support/pom.xml b/integration-tests/support/pom.xml
index a2a1ea7..bcfd9fd 100644
--- a/integration-tests/support/pom.xml
+++ b/integration-tests/support/pom.xml
@@ -23,7 +23,7 @@
 	<parent>
 		<groupId>org.apache.shiro.integrationtests</groupId>
 		<artifactId>shiro-integration-tests</artifactId>
-		<version>1.5.3-SNAPSHOT</version>
+		<version>2.0.0-SNAPSHOT</version>
 		<relativePath>../pom.xml</relativePath>
 	</parent>
 
@@ -32,14 +32,14 @@
 
 	<dependencies>
 	    <dependency>
-		<groupId>org.apache.taglibs</groupId>
-		<artifactId>taglibs-standard-spec</artifactId>
-		<scope>compile</scope>
+            <groupId>org.apache.taglibs</groupId>
+            <artifactId>taglibs-standard-spec</artifactId>
+            <scope>compile</scope>
 	    </dependency>
 	    <dependency>
-		<groupId>org.apache.taglibs</groupId>
-		<artifactId>taglibs-standard-impl</artifactId>
-		<scope>compile</scope>
+            <groupId>org.apache.taglibs</groupId>
+            <artifactId>taglibs-standard-impl</artifactId>
+            <scope>compile</scope>
 	    </dependency>
 	    <dependency>
 	        <groupId>javax.servlet</groupId>
diff --git a/lang/pom.xml b/lang/pom.xml
index c335a67..275a7d2 100644
--- a/lang/pom.xml
+++ b/lang/pom.xml
@@ -23,7 +23,7 @@
     <parent>
         <groupId>org.apache.shiro</groupId>
         <artifactId>shiro-root</artifactId>
-        <version>1.5.3-SNAPSHOT</version>
+        <version>2.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 
diff --git a/lang/src/main/java/org/apache/shiro/io/XmlSerializer.java b/lang/src/main/java/org/apache/shiro/io/XmlSerializer.java
index 12c2a39..583a8ce 100644
--- a/lang/src/main/java/org/apache/shiro/io/XmlSerializer.java
+++ b/lang/src/main/java/org/apache/shiro/io/XmlSerializer.java
@@ -32,8 +32,9 @@
  * <p/>
  * <b>NOTE:</b> The JavaBeans XMLEncoder/XMLDecoder only successfully encode/decode objects when they are
  * JavaBeans compatible!
- * 
+ *
  * @since 0.9
+ * @deprecated This class should not be used directly because of unsecure XMLEncoder/XMLDecoder usage.
  */
 public class XmlSerializer implements Serializer {
 
diff --git a/pom.xml b/pom.xml
index 75e4633..586d77c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -24,13 +24,13 @@
     <parent>
         <groupId>org.apache</groupId>
         <artifactId>apache</artifactId>
-        <version>21</version>
+        <version>23</version>
     </parent>
 
     <groupId>org.apache.shiro</groupId>
     <artifactId>shiro-root</artifactId>
     <packaging>pom</packaging>
-    <version>1.5.3-SNAPSHOT</version>
+    <version>2.0.0-SNAPSHOT</version>
 
     <name>Apache Shiro</name>
     <url>https://shiro.apache.org/</url>
@@ -81,7 +81,7 @@
         <cas.client.core.version>3.2.2</cas.client.core.version>
         <commons.beanutils.version>1.9.4</commons.beanutils.version>
         <commons.cli.version>1.4</commons.cli.version>
-        <commons.codec.version>1.13</commons.codec.version>
+        <commons.codec.version>1.14</commons.codec.version>
         <commons.configuration2.version>2.7</commons.configuration2.version>
         <commons.lang3.version>3.9</commons.lang3.version>
         <commons.logging.version>1.2</commons.logging.version>
@@ -89,11 +89,11 @@
              modules' OSGi metadata: -->
         <ehcache.version>2.6.11</ehcache.version>
         <!-- Don't change this version without also changing the shiro-hazelcast and shiro-features OSGi metadata: -->
-        <hazelcast.version>3.12.1</hazelcast.version>
+        <hazelcast.version>3.12.6</hazelcast.version>
         <hsqldb.version>2.5.0</hsqldb.version>
         <javax.annotation.api.version>1.3.2</javax.annotation.api.version>
         <jdk.version>1.8</jdk.version>
-        <jetty.version>9.4.20.v20190813</jetty.version>
+        <jetty.version>9.4.27.v20200227</jetty.version>
         <owasp.java.encoder.version>1.2.2</owasp.java.encoder.version>
         <!-- Don't change this version without also changing the shiro-quartz and shiro-features
              modules' OSGi metadata: -->
@@ -101,11 +101,11 @@
         <slf4j.version>1.7.26</slf4j.version>
         <logback.version>1.2.3</logback.version>
         <log4j.version>1.2.17</log4j.version>
-        <spring.version>5.2.3.RELEASE</spring.version>
-        <spring-boot.version>2.2.4.RELEASE</spring-boot.version>
+        <spring.version>5.2.5.RELEASE</spring.version>
+        <spring-boot.version>2.2.6.RELEASE</spring-boot.version>
         <guice.version>4.2.2</guice.version>
         <jaxrs.api.version>2.0.1</jaxrs.api.version>
-        <htmlunit.version>2.36.0</htmlunit.version>
+        <htmlunit.version>2.39.0</htmlunit.version>
 
         <!-- Test 3rd-party dependencies: -->
         <easymock.version>4.0.2</easymock.version>
diff --git a/samples/aspectj/pom.xml b/samples/aspectj/pom.xml
index df73b8b..748cb0b 100644
--- a/samples/aspectj/pom.xml
+++ b/samples/aspectj/pom.xml
@@ -23,7 +23,7 @@
 	<parent>
         <groupId>org.apache.shiro.samples</groupId>
         <artifactId>shiro-samples</artifactId>
-        <version>1.5.3-SNAPSHOT</version>
+        <version>2.0.0-SNAPSHOT</version>
 	    <relativePath>../pom.xml</relativePath>
         </parent>
 
diff --git a/samples/guice/pom.xml b/samples/guice/pom.xml
index bae58e0..d1ee44d 100644
--- a/samples/guice/pom.xml
+++ b/samples/guice/pom.xml
@@ -21,7 +21,7 @@
 	<parent>
         <groupId>org.apache.shiro.samples</groupId>
         <artifactId>shiro-samples</artifactId>
-		<version>1.5.3-SNAPSHOT</version>
+		<version>2.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
 	</parent>
 
diff --git a/samples/jaxrs/pom.xml b/samples/jaxrs/pom.xml
index 13178d6..cf5dfb2 100644
--- a/samples/jaxrs/pom.xml
+++ b/samples/jaxrs/pom.xml
@@ -23,7 +23,7 @@
     <parent>
         <groupId>org.apache.shiro.samples</groupId>
         <artifactId>shiro-samples</artifactId>
-        <version>1.5.3-SNAPSHOT</version>
+        <version>2.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 
diff --git a/samples/pom.xml b/samples/pom.xml
index 55d9a3c..3ae24a3 100644
--- a/samples/pom.xml
+++ b/samples/pom.xml
@@ -22,7 +22,7 @@
     <parent>
         <groupId>org.apache.shiro</groupId>
         <artifactId>shiro-root</artifactId>
-        <version>1.5.3-SNAPSHOT</version>
+        <version>2.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 
diff --git a/samples/quickstart-guice/pom.xml b/samples/quickstart-guice/pom.xml
index 36af5a7..cdd2eb2 100644
--- a/samples/quickstart-guice/pom.xml
+++ b/samples/quickstart-guice/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <groupId>org.apache.shiro.samples</groupId>
         <artifactId>shiro-samples</artifactId>
-        <version>1.5.3-SNAPSHOT</version>
+        <version>2.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 
diff --git a/samples/quickstart/pom.xml b/samples/quickstart/pom.xml
index 3424501..8d781e5 100644
--- a/samples/quickstart/pom.xml
+++ b/samples/quickstart/pom.xml
@@ -23,7 +23,7 @@
     <parent>
         <groupId>org.apache.shiro.samples</groupId>
         <artifactId>shiro-samples</artifactId>
-        <version>1.5.3-SNAPSHOT</version>
+        <version>2.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 
diff --git a/samples/servlet-plugin/pom.xml b/samples/servlet-plugin/pom.xml
index c0cd893..67f79f7 100644
--- a/samples/servlet-plugin/pom.xml
+++ b/samples/servlet-plugin/pom.xml
@@ -23,7 +23,7 @@
     <parent>
         <groupId>org.apache.shiro.samples</groupId>
         <artifactId>shiro-samples</artifactId>
-        <version>1.5.3-SNAPSHOT</version>
+        <version>2.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 
diff --git a/samples/spring-boot-web/pom.xml b/samples/spring-boot-web/pom.xml
index f6eb2da..0f64ae1 100644
--- a/samples/spring-boot-web/pom.xml
+++ b/samples/spring-boot-web/pom.xml
@@ -25,7 +25,7 @@
     <parent>
         <groupId>org.apache.shiro.samples</groupId>
         <artifactId>shiro-samples</artifactId>
-        <version>1.5.3-SNAPSHOT</version>
+        <version>2.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 
diff --git a/samples/spring-boot/pom.xml b/samples/spring-boot/pom.xml
index 7d25a87..e7991d5 100644
--- a/samples/spring-boot/pom.xml
+++ b/samples/spring-boot/pom.xml
@@ -25,7 +25,7 @@
     <parent>
         <groupId>org.apache.shiro.samples</groupId>
         <artifactId>shiro-samples</artifactId>
-        <version>1.5.3-SNAPSHOT</version>
+        <version>2.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 
diff --git a/samples/spring-hibernate/pom.xml b/samples/spring-hibernate/pom.xml
index 3fc22bc..74c87dd 100644
--- a/samples/spring-hibernate/pom.xml
+++ b/samples/spring-hibernate/pom.xml
@@ -23,7 +23,7 @@
     <parent>
         <groupId>org.apache.shiro.samples</groupId>
         <artifactId>shiro-samples</artifactId>
-        <version>1.5.3-SNAPSHOT</version>
+        <version>2.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 
diff --git a/samples/spring-mvc/pom.xml b/samples/spring-mvc/pom.xml
index 5e6a1ff..253823d 100644
--- a/samples/spring-mvc/pom.xml
+++ b/samples/spring-mvc/pom.xml
@@ -23,7 +23,7 @@
     <parent>
         <groupId>org.apache.shiro.samples</groupId>
         <artifactId>shiro-samples</artifactId>
-        <version>1.5.3-SNAPSHOT</version>
+        <version>2.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 
diff --git a/samples/spring/pom.xml b/samples/spring/pom.xml
index 05ba6e2..a40d458 100644
--- a/samples/spring/pom.xml
+++ b/samples/spring/pom.xml
@@ -23,7 +23,7 @@
     <parent>
         <groupId>org.apache.shiro.samples</groupId>
         <artifactId>shiro-samples</artifactId>
-        <version>1.5.3-SNAPSHOT</version>
+        <version>2.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 
diff --git a/samples/web/pom.xml b/samples/web/pom.xml
index 6341476..ac3ec71 100644
--- a/samples/web/pom.xml
+++ b/samples/web/pom.xml
@@ -23,7 +23,7 @@
     <parent>
         <groupId>org.apache.shiro.samples</groupId>
         <artifactId>shiro-samples</artifactId>
-        <version>1.5.3-SNAPSHOT</version>
+        <version>2.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 
diff --git a/support/aspectj/pom.xml b/support/aspectj/pom.xml
index a136a10..68b1a87 100644
--- a/support/aspectj/pom.xml
+++ b/support/aspectj/pom.xml
@@ -22,7 +22,7 @@
     <parent>
         <groupId>org.apache.shiro</groupId>
         <artifactId>shiro-support</artifactId>
-        <version>1.5.3-SNAPSHOT</version>
+        <version>2.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 
diff --git a/support/cas/pom.xml b/support/cas/pom.xml
index 51028e1..c0909ae 100644
--- a/support/cas/pom.xml
+++ b/support/cas/pom.xml
@@ -22,7 +22,7 @@
     <parent>
         <groupId>org.apache.shiro</groupId>
         <artifactId>shiro-support</artifactId>
-        <version>1.5.3-SNAPSHOT</version>
+        <version>2.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 
diff --git a/support/ehcache/pom.xml b/support/ehcache/pom.xml
index ce39f08..b56cce3 100644
--- a/support/ehcache/pom.xml
+++ b/support/ehcache/pom.xml
@@ -22,7 +22,7 @@
     <parent>
         <groupId>org.apache.shiro</groupId>
         <artifactId>shiro-support</artifactId>
-        <version>1.5.3-SNAPSHOT</version>
+        <version>2.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 
diff --git a/support/features/pom.xml b/support/features/pom.xml
index 0ba70b8..845b453 100644
--- a/support/features/pom.xml
+++ b/support/features/pom.xml
@@ -22,7 +22,7 @@
     <parent>
         <groupId>org.apache.shiro</groupId>
         <artifactId>shiro-support</artifactId>
-        <version>1.5.3-SNAPSHOT</version>
+        <version>2.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 
@@ -40,7 +40,7 @@
         <!-- Not a Shiro dependency - used for quartz bundle resolution only (see features.xml): -->
         <commons.collections.version>3.2.2</commons.collections.version>
         <!-- karaf plugin version -->
-        <karaf.version>4.2.7</karaf.version>
+        <karaf.version>4.2.8</karaf.version>
     </properties>
 
     <dependencies>
diff --git a/support/guice/pom.xml b/support/guice/pom.xml
index 9d9e8b3..66ade20 100644
--- a/support/guice/pom.xml
+++ b/support/guice/pom.xml
@@ -22,7 +22,7 @@
     <parent>
         <groupId>org.apache.shiro</groupId>
         <artifactId>shiro-support</artifactId>
-        <version>1.5.3-SNAPSHOT</version>
+        <version>2.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 
diff --git a/support/guice/src/test/java/org/apache/shiro/guice/web/FilterConfigTest.java b/support/guice/src/test/java/org/apache/shiro/guice/web/FilterConfigTest.java
index 75324ad..3919207 100644
--- a/support/guice/src/test/java/org/apache/shiro/guice/web/FilterConfigTest.java
+++ b/support/guice/src/test/java/org/apache/shiro/guice/web/FilterConfigTest.java
@@ -85,8 +85,7 @@
     private HttpServletRequest createMockRequest(String path) {

         HttpServletRequest request = createNiceMock(HttpServletRequest.class);

 

-        expect(request.getAttribute(WebUtils.INCLUDE_CONTEXT_PATH_ATTRIBUTE)).andReturn(null).anyTimes();

-        expect(request.getContextPath()).andReturn("");

+        expect(request.getServletPath()).andReturn("");

         expect(request.getPathInfo()).andReturn(path);

         replay(request);

         return request;

diff --git a/support/guice/src/test/java/org/apache/shiro/guice/web/ShiroWebModuleTest.java b/support/guice/src/test/java/org/apache/shiro/guice/web/ShiroWebModuleTest.java
index ff50d0f..9931d01 100644
--- a/support/guice/src/test/java/org/apache/shiro/guice/web/ShiroWebModuleTest.java
+++ b/support/guice/src/test/java/org/apache/shiro/guice/web/ShiroWebModuleTest.java
@@ -177,11 +177,13 @@
         servletContext.setAttribute(eq(EnvironmentLoader.ENVIRONMENT_ATTRIBUTE_KEY), EasyMock.anyObject());

         expect(request.getAttribute("javax.servlet.include.context_path")).andReturn("").anyTimes();

         expect(request.getCharacterEncoding()).andReturn("UTF-8").anyTimes();

-        expect(request.getAttribute("javax.servlet.include.request_uri")).andReturn("/test_authc");

-        expect(request.getAttribute("javax.servlet.include.request_uri")).andReturn("/test_custom_filter");

-        expect(request.getAttribute("javax.servlet.include.request_uri")).andReturn("/test_authc_basic");

-        expect(request.getAttribute("javax.servlet.include.request_uri")).andReturn("/test_perms");

-        expect(request.getAttribute("javax.servlet.include.request_uri")).andReturn("/multiple_configs");

+        expect(request.getAttribute("javax.servlet.include.path_info")).andReturn(null).anyTimes();

+        expect(request.getPathInfo()).andReturn(null).anyTimes();

+        expect(request.getAttribute("javax.servlet.include.servlet_path")).andReturn("/test_authc");

+        expect(request.getAttribute("javax.servlet.include.servlet_path")).andReturn("/test_custom_filter");

+        expect(request.getAttribute("javax.servlet.include.servlet_path")).andReturn("/test_authc_basic");

+        expect(request.getAttribute("javax.servlet.include.servlet_path")).andReturn("/test_perms");

+        expect(request.getAttribute("javax.servlet.include.servlet_path")).andReturn("/multiple_configs");

         replay(servletContext, request);

 

         Injector injector = Guice.createInjector(new ShiroWebModule(servletContext) {

diff --git a/support/guice/src/test/java/org/apache/shiro/guice/web/SimpleFilterChainResolverTest.java b/support/guice/src/test/java/org/apache/shiro/guice/web/SimpleFilterChainResolverTest.java
index d500da8..586a2b9 100644
--- a/support/guice/src/test/java/org/apache/shiro/guice/web/SimpleFilterChainResolverTest.java
+++ b/support/guice/src/test/java/org/apache/shiro/guice/web/SimpleFilterChainResolverTest.java
@@ -77,8 +77,8 @@
         ServletResponse response = ctrl.createMock(HttpServletResponse.class);

         FilterChain originalChain = ctrl.createMock(FilterChain.class);

 

-        expect(request.getAttribute(WebUtils.INCLUDE_CONTEXT_PATH_ATTRIBUTE)).andReturn("/context");

-        expect(request.getAttribute(WebUtils.INCLUDE_REQUEST_URI_ATTRIBUTE)).andReturn("/mychain");

+        expect(request.getAttribute(WebUtils.INCLUDE_SERVLET_PATH_ATTRIBUTE)).andReturn("/mychain");

+        expect(request.getAttribute(WebUtils.INCLUDE_PATH_INFO_ATTRIBUTE)).andReturn("");

 

         expect(request.getCharacterEncoding()).andStubReturn(null);

 

@@ -108,8 +108,8 @@
 

         ctrl.reset();

 

-        expect(request.getAttribute(WebUtils.INCLUDE_CONTEXT_PATH_ATTRIBUTE)).andReturn("/context");

-        expect(request.getAttribute(WebUtils.INCLUDE_REQUEST_URI_ATTRIBUTE)).andReturn("/nochain");

+        expect(request.getAttribute(WebUtils.INCLUDE_SERVLET_PATH_ATTRIBUTE)).andReturn("/nochain");

+        expect(request.getAttribute(WebUtils.INCLUDE_PATH_INFO_ATTRIBUTE)).andReturn("");

 

         expect(request.getCharacterEncoding()).andStubReturn(null);

 

diff --git a/support/hazelcast/pom.xml b/support/hazelcast/pom.xml
index 56bfa54..b5d3bb8 100644
--- a/support/hazelcast/pom.xml
+++ b/support/hazelcast/pom.xml
@@ -22,7 +22,7 @@
     <parent>
         <groupId>org.apache.shiro</groupId>
         <artifactId>shiro-support</artifactId>
-        <version>1.5.3-SNAPSHOT</version>
+        <version>2.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 
diff --git a/support/jaxrs/pom.xml b/support/jaxrs/pom.xml
index e16a76a..3302e51 100644
--- a/support/jaxrs/pom.xml
+++ b/support/jaxrs/pom.xml
@@ -22,7 +22,7 @@
     <parent>
         <groupId>org.apache.shiro</groupId>
         <artifactId>shiro-support</artifactId>
-        <version>1.5.3-SNAPSHOT</version>
+        <version>2.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 
diff --git a/support/pom.xml b/support/pom.xml
index 9bb4cee..fdc223f 100644
--- a/support/pom.xml
+++ b/support/pom.xml
@@ -22,7 +22,7 @@
     <parent>
         <groupId>org.apache.shiro</groupId>
         <artifactId>shiro-root</artifactId>
-        <version>1.5.3-SNAPSHOT</version>
+        <version>2.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 
diff --git a/support/quartz/pom.xml b/support/quartz/pom.xml
index fa9cfec..190659f 100644
--- a/support/quartz/pom.xml
+++ b/support/quartz/pom.xml
@@ -22,7 +22,7 @@
     <parent>
         <groupId>org.apache.shiro</groupId>
         <artifactId>shiro-support</artifactId>
-        <version>1.5.3-SNAPSHOT</version>
+        <version>2.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 
diff --git a/support/servlet-plugin/pom.xml b/support/servlet-plugin/pom.xml
index 0467c7e..2d24a50 100644
--- a/support/servlet-plugin/pom.xml
+++ b/support/servlet-plugin/pom.xml
@@ -25,7 +25,7 @@
     <parent>
         <groupId>org.apache.shiro</groupId>
         <artifactId>shiro-support</artifactId>
-        <version>1.5.3-SNAPSHOT</version>
+        <version>2.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 
diff --git a/support/spring-boot/pom.xml b/support/spring-boot/pom.xml
index 01a01f8..a3dc955 100644
--- a/support/spring-boot/pom.xml
+++ b/support/spring-boot/pom.xml
@@ -22,7 +22,7 @@
     <parent>
         <groupId>org.apache.shiro</groupId>
         <artifactId>shiro-support</artifactId>
-        <version>1.5.3-SNAPSHOT</version>
+        <version>2.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 
diff --git a/support/spring-boot/spring-boot-starter/pom.xml b/support/spring-boot/spring-boot-starter/pom.xml
index 5d274d9..f797e6d 100644
--- a/support/spring-boot/spring-boot-starter/pom.xml
+++ b/support/spring-boot/spring-boot-starter/pom.xml
@@ -25,7 +25,7 @@
     <parent>
         <groupId>org.apache.shiro</groupId>
         <artifactId>shiro-spring-boot</artifactId>
-        <version>1.5.3-SNAPSHOT</version>
+        <version>2.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 
diff --git a/support/spring-boot/spring-boot-web-starter/pom.xml b/support/spring-boot/spring-boot-web-starter/pom.xml
index de32dfe..0a69002 100644
--- a/support/spring-boot/spring-boot-web-starter/pom.xml
+++ b/support/spring-boot/spring-boot-web-starter/pom.xml
@@ -25,7 +25,7 @@
     <parent>
         <groupId>org.apache.shiro</groupId>
         <artifactId>shiro-spring-boot</artifactId>
-        <version>1.5.3-SNAPSHOT</version>
+        <version>2.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 
diff --git a/support/spring/pom.xml b/support/spring/pom.xml
index 42f9b73..254373f 100644
--- a/support/spring/pom.xml
+++ b/support/spring/pom.xml
@@ -22,7 +22,7 @@
     <parent>
         <groupId>org.apache.shiro</groupId>
         <artifactId>shiro-support</artifactId>
-        <version>1.5.3-SNAPSHOT</version>
+        <version>2.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 
diff --git a/test-coverage/pom.xml b/test-coverage/pom.xml
index 44b3250..1abe085 100644
--- a/test-coverage/pom.xml
+++ b/test-coverage/pom.xml
@@ -22,7 +22,7 @@
     <parent>
         <groupId>org.apache.shiro</groupId>
         <artifactId>shiro-root</artifactId>
-        <version>1.5.3-SNAPSHOT</version>
+        <version>2.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 
diff --git a/tools/hasher/pom.xml b/tools/hasher/pom.xml
index 0fefa73..9af02f8 100644
--- a/tools/hasher/pom.xml
+++ b/tools/hasher/pom.xml
@@ -22,7 +22,7 @@
     <parent>
         <groupId>org.apache.shiro.tools</groupId>
         <artifactId>shiro-tools</artifactId>
-        <version>1.5.3-SNAPSHOT</version>
+        <version>2.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 
diff --git a/tools/pom.xml b/tools/pom.xml
index 89220dd..01c371c 100644
--- a/tools/pom.xml
+++ b/tools/pom.xml
@@ -22,7 +22,7 @@
     <parent>
         <groupId>org.apache.shiro</groupId>
         <artifactId>shiro-root</artifactId>
-        <version>1.5.3-SNAPSHOT</version>
+        <version>2.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 
diff --git a/web/pom.xml b/web/pom.xml
index 9078394..7de72ac 100644
--- a/web/pom.xml
+++ b/web/pom.xml
@@ -23,7 +23,7 @@
     <parent>
         <groupId>org.apache.shiro</groupId>
         <artifactId>shiro-root</artifactId>
-        <version>1.5.3-SNAPSHOT</version>
+        <version>2.0.0-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
 
diff --git a/web/src/main/java/org/apache/shiro/web/util/WebUtils.java b/web/src/main/java/org/apache/shiro/web/util/WebUtils.java
index 0700e67..b9c9f62 100644
--- a/web/src/main/java/org/apache/shiro/web/util/WebUtils.java
+++ b/web/src/main/java/org/apache/shiro/web/util/WebUtils.java
@@ -109,16 +109,7 @@
      * @return the path within the web application
      */
     public static String getPathWithinApplication(HttpServletRequest request) {
-        String contextPath = getContextPath(request);
-        String requestUri = getRequestUri(request);
-        if (StringUtils.startsWithIgnoreCase(requestUri, contextPath)) {
-            // Normal case: URI contains context path.
-            String path = requestUri.substring(contextPath.length());
-            return (StringUtils.hasText(path) ? path : "/");
-        } else {
-            // Special case: rather unusual.
-            return requestUri;
-        }
+        return normalize(removeSemicolon(getServletPath(request) + getPathInfo(request)));
     }
 
     /**
@@ -132,17 +123,27 @@
      *
      * @param request current HTTP request
      * @return the request URI
+     * @deprecated use getPathWithinApplication() to get the path minus the context path, or call HttpServletRequest.getRequestURI() directly from your code.
      */
+    @Deprecated
     public static String getRequestUri(HttpServletRequest request) {
         String uri = (String) request.getAttribute(INCLUDE_REQUEST_URI_ATTRIBUTE);
         if (uri == null) {
-            uri = valueOrEmpty(request.getContextPath()) + "/" +
-                  valueOrEmpty(request.getServletPath()) +
-                  valueOrEmpty(request.getPathInfo());
+            uri = request.getRequestURI();
         }
         return normalize(decodeAndCleanUriString(request, uri));
     }
 
+    private static String getServletPath(HttpServletRequest request) {
+        String servletPath = (String) request.getAttribute(INCLUDE_SERVLET_PATH_ATTRIBUTE);
+        return servletPath != null ? servletPath : valueOrEmpty(request.getServletPath());
+    }
+
+    private static String getPathInfo(HttpServletRequest request) {
+        String pathInfo = (String) request.getAttribute(INCLUDE_PATH_INFO_ATTRIBUTE);
+        return pathInfo != null ? pathInfo : valueOrEmpty(request.getPathInfo());
+    }
+
     private static String valueOrEmpty(String input) {
         if (input == null) {
             return "";
@@ -240,6 +241,10 @@
      */
     private static String decodeAndCleanUriString(HttpServletRequest request, String uri) {
         uri = decodeRequestString(request, uri);
+        return removeSemicolon(uri);
+    }
+
+    private static String removeSemicolon(String uri) {
         int semicolonIndex = uri.indexOf(';');
         return (semicolonIndex != -1 ? uri.substring(0, semicolonIndex) : uri);
     }
diff --git a/web/src/test/groovy/org/apache/shiro/web/util/WebUtilsTest.groovy b/web/src/test/groovy/org/apache/shiro/web/util/WebUtilsTest.groovy
index 26be858..7956a10 100644
--- a/web/src/test/groovy/org/apache/shiro/web/util/WebUtilsTest.groovy
+++ b/web/src/test/groovy/org/apache/shiro/web/util/WebUtilsTest.groovy
@@ -143,63 +143,85 @@
     @Test
     void testGetRequestUriWithServlet() {
 
-        dotTestGetPathWithinApplicationFromRequest("/", "/servlet", "/foobar", "/servlet/foobar")
-        dotTestGetPathWithinApplicationFromRequest("", "/servlet", "/foobar", "/servlet/foobar")
-        dotTestGetPathWithinApplicationFromRequest("", "servlet", "/foobar", "/servlet/foobar")
-        dotTestGetPathWithinApplicationFromRequest("/", "servlet", "/foobar", "/servlet/foobar")
-        dotTestGetPathWithinApplicationFromRequest("//", "servlet", "/foobar", "/servlet/foobar")
-        dotTestGetPathWithinApplicationFromRequest("//", "//servlet", "//foobar", "/servlet/foobar")
-        dotTestGetPathWithinApplicationFromRequest("/context-path", "/servlet", "/foobar", "/servlet/foobar")
-        dotTestGetPathWithinApplicationFromRequest("//context-path", "//servlet", "//foobar", "/servlet/foobar")
-        dotTestGetPathWithinApplicationFromRequest("//context-path", "/servlet", "/../servlet/other", "/servlet/other")
-        dotTestGetPathWithinApplicationFromRequest("//context-path", "/asdf", "/../servlet/other", "/servlet/other")
-        dotTestGetPathWithinApplicationFromRequest("//context-path", "/asdf", ";/../servlet/other", "/asdf")
-        dotTestGetPathWithinApplicationFromRequest("/context%2525path", "/servlet", "/foobar", "/servlet/foobar")
-        dotTestGetPathWithinApplicationFromRequest("/c%6Fntext%20path", "/servlet", "/foobar", "/servlet/foobar")
-        dotTestGetPathWithinApplicationFromRequest("/context path", "/servlet", "/foobar", "/servlet/foobar")
-        dotTestGetPathWithinApplicationFromRequest("", null, null, "/")
-        dotTestGetPathWithinApplicationFromRequest("", "index.jsp", null, "/index.jsp")
+        dotTestGetPathWithinApplicationFromRequest("/servlet", "/foobar", "/servlet/foobar")
+        dotTestGetPathWithinApplicationFromRequest("/servlet", "/foobar", "/servlet/foobar")
+        dotTestGetPathWithinApplicationFromRequest("servlet", "/foobar", "/servlet/foobar")
+        dotTestGetPathWithinApplicationFromRequest("servlet", "/foobar", "/servlet/foobar")
+        dotTestGetPathWithinApplicationFromRequest("servlet", "/foobar", "/servlet/foobar")
+        dotTestGetPathWithinApplicationFromRequest("//servlet", "//foobar", "/servlet/foobar")
+        dotTestGetPathWithinApplicationFromRequest("/servlet", "/foobar", "/servlet/foobar")
+        dotTestGetPathWithinApplicationFromRequest("//servlet", "//foobar", "/servlet/foobar")
+        dotTestGetPathWithinApplicationFromRequest("/servlet", "/../servlet/other", "/servlet/other")
+        dotTestGetPathWithinApplicationFromRequest("/asdf", "/../servlet/other", "/servlet/other")
+        dotTestGetPathWithinApplicationFromRequest("/asdf/foo", ";/../servlet/other", "/asdf/foo")
+        dotTestGetPathWithinApplicationFromRequest("/servlet", "/foobar", "/servlet/foobar")
+        dotTestGetPathWithinApplicationFromRequest("/servlet", "/foobar", "/servlet/foobar")
+        dotTestGetPathWithinApplicationFromRequest("/servlet", "/foobar", "/servlet/foobar")
+        dotTestGetPathWithinApplicationFromRequest(null, null, "/")
+        dotTestGetPathWithinApplicationFromRequest("index.jsp", null, "/index.jsp")
     }
 
     @Test
     void testGetPathWithinApplication() {
 
-        doTestGetPathWithinApplication("/", "/foobar", "/foobar");
-        doTestGetPathWithinApplication("", "/foobar", "/foobar");
-        doTestGetPathWithinApplication("", "foobar", "/foobar");
-        doTestGetPathWithinApplication("/", "foobar", "/foobar");
-        doTestGetPathWithinApplication("//", "foobar", "/foobar");
-        doTestGetPathWithinApplication("//", "//foobar", "/foobar");
-        doTestGetPathWithinApplication("/context-path", "/context-path/foobar", "/foobar");
-        doTestGetPathWithinApplication("/context-path", "/context-path/foobar/", "/foobar/");
-        doTestGetPathWithinApplication("//context-path", "//context-path/foobar", "/foobar");
-        doTestGetPathWithinApplication("//context-path", "//context-path//foobar", "/foobar");
-        doTestGetPathWithinApplication("//context-path", "//context-path/remove-one/remove-two/../../././/foobar", "/foobar");
-        doTestGetPathWithinApplication("//context-path", "//context-path//../../././/foobar", null);
-        doTestGetPathWithinApplication("/context%2525path", "/context%2525path/foobar", "/foobar");
-        doTestGetPathWithinApplication("/c%6Fntext%20path", "/c%6Fntext%20path/foobar", "/foobar");
-        doTestGetPathWithinApplication("/context path", "/context path/foobar", "/foobar");
-
+        doTestGetPathWithinApplication("/foobar", null, "/foobar");
+        doTestGetPathWithinApplication("/foobar", "", "/foobar");
+        doTestGetPathWithinApplication("", "/", "/");
+        doTestGetPathWithinApplication("", null, "/");
+        doTestGetPathWithinApplication("/foobar", "//", "/foobar/");
+        doTestGetPathWithinApplication("/foobar", "//extra", "/foobar/extra");
+        doTestGetPathWithinApplication("/foobar", "//extra///", "/foobar/extra/");
+        doTestGetPathWithinApplication("/foo bar", "/path info" ,"/foo bar/path info");
     }
 
-    void doTestGetPathWithinApplication(String contextPath, String requestUri, String expectedValue) {
+    @Test
+    void testGetRequestURI() {
+        doTestGetRequestURI("/foobar", "/foobar")
+        doTestGetRequestURI( "/foobar/", "/foobar/")
+        doTestGetRequestURI("",  "/");
+        doTestGetRequestURI("foobar", "/foobar");
+        doTestGetRequestURI("//foobar", "/foobar");
+        doTestGetRequestURI("//foobar///", "/foobar/");
+        doTestGetRequestURI("/context-path/foobar", "/context-path/foobar");
+        doTestGetRequestURI("/context-path/foobar/", "/context-path/foobar/");
+        doTestGetRequestURI("//context-path/foobar", "/context-path/foobar");
+        doTestGetRequestURI("//context-path//foobar", "/context-path/foobar");
+        doTestGetRequestURI("//context-path/remove-one/remove-two/../../././/foobar", "/context-path/foobar");
+        doTestGetRequestURI("//context-path//../../././/foobar", null);
+        doTestGetRequestURI("/context%2525path/foobar", "/context%25path/foobar");
+        doTestGetRequestURI("/c%6Fntext%20path/foobar", "/context path/foobar");
+        doTestGetRequestURI("/context path/foobar", "/context path/foobar");
+    }
+
+    void doTestGetPathWithinApplication(String servletPath, String pathInfo, String expectedValue) {
 
         def request = createMock(HttpServletRequest)
-        expect(request.getAttribute(WebUtils.INCLUDE_CONTEXT_PATH_ATTRIBUTE)).andReturn(contextPath)
-        expect(request.getAttribute(WebUtils.INCLUDE_REQUEST_URI_ATTRIBUTE)).andReturn(requestUri)
-        expect(request.getCharacterEncoding()).andReturn("UTF-8").times(2)
+        expect(request.getAttribute(WebUtils.INCLUDE_SERVLET_PATH_ATTRIBUTE)).andReturn(servletPath)
+        expect(request.getAttribute(WebUtils.INCLUDE_PATH_INFO_ATTRIBUTE)).andReturn(pathInfo)
+        if (pathInfo == null) {
+            expect(request.getPathInfo()).andReturn(null) // path info can be null
+        }
         replay request
         assertEquals expectedValue, WebUtils.getPathWithinApplication(request)
         verify request
     }
 
-    void dotTestGetPathWithinApplicationFromRequest(String contextPath, String servletPath, String pathInfo, String expectedValue) {
+    void doTestGetRequestURI(String rawRequestUri, String expectedValue) {
+
+        def request = createMock(HttpServletRequest)
+        expect(request.getAttribute(WebUtils.INCLUDE_REQUEST_URI_ATTRIBUTE)).andReturn(rawRequestUri)
+        expect(request.getCharacterEncoding()).andReturn("UTF-8").times(1)
+        replay request
+        assertEquals expectedValue, WebUtils.getRequestUri(request)
+        verify request
+    }
+
+    void dotTestGetPathWithinApplicationFromRequest(String servletPath, String pathInfo, String expectedValue) {
 
         HttpServletRequest request = createMock(HttpServletRequest)
-        expect(request.getAttribute(WebUtils.INCLUDE_CONTEXT_PATH_ATTRIBUTE)).andReturn(null)
-        expect(request.getAttribute(WebUtils.INCLUDE_REQUEST_URI_ATTRIBUTE)).andReturn(null)
+        expect(request.getAttribute(WebUtils.INCLUDE_SERVLET_PATH_ATTRIBUTE)).andReturn(null)
+        expect(request.getAttribute(WebUtils.INCLUDE_PATH_INFO_ATTRIBUTE)).andReturn(null)
         expect(request.getServletPath()).andReturn(servletPath)
-        expect(request.getContextPath()).andReturn(contextPath).times(2)
         expect(request.getPathInfo()).andReturn(pathInfo)
         expect(request.getCharacterEncoding()).andReturn("UTF-8").anyTimes()
         replay request
diff --git a/web/src/test/java/org/apache/shiro/web/filter/mgt/PathMatchingFilterChainResolverTest.java b/web/src/test/java/org/apache/shiro/web/filter/mgt/PathMatchingFilterChainResolverTest.java
index 99bac0d..963e89e 100644
--- a/web/src/test/java/org/apache/shiro/web/filter/mgt/PathMatchingFilterChainResolverTest.java
+++ b/web/src/test/java/org/apache/shiro/web/filter/mgt/PathMatchingFilterChainResolverTest.java
@@ -97,8 +97,6 @@
         //ensure at least one chain is defined:
         resolver.getFilterChainManager().addToChain("/index.html", "authcBasic");
 
-        expect(request.getAttribute(WebUtils.INCLUDE_CONTEXT_PATH_ATTRIBUTE)).andReturn(null).anyTimes();
-        expect(request.getContextPath()).andReturn("");
         expect(request.getServletPath()).andReturn("");
         expect(request.getPathInfo()).andReturn("/index.html");
         replay(request);
@@ -117,8 +115,6 @@
         //ensure at least one chain is defined:
         resolver.getFilterChainManager().addToChain("/index.html", "authcBasic");
 
-        expect(request.getAttribute(WebUtils.INCLUDE_CONTEXT_PATH_ATTRIBUTE)).andReturn(null).anyTimes();
-        expect(request.getContextPath()).andReturn("");
         expect(request.getServletPath()).andReturn("/");
         expect(request.getPathInfo()).andReturn("./index.html");
         replay(request);
@@ -136,9 +132,6 @@
 
         //ensure at least one chain is defined:
         resolver.getFilterChainManager().addToChain("/index.html", "authcBasic");
-
-        expect(request.getAttribute(WebUtils.INCLUDE_CONTEXT_PATH_ATTRIBUTE)).andReturn(null).anyTimes();
-        expect(request.getContextPath()).andReturn("");
         expect(request.getServletPath()).andReturn("/public/");
         expect(request.getPathInfo()).andReturn("../index.html");
         replay(request);
@@ -157,8 +150,6 @@
         //ensure at least one chain is defined:
         resolver.getFilterChainManager().addToChain("/index.html", "authcBasic");
 
-        expect(request.getAttribute(WebUtils.INCLUDE_CONTEXT_PATH_ATTRIBUTE)).andReturn(null).anyTimes();
-        expect(request.getContextPath()).andReturn("");
         expect(request.getServletPath()).andReturn("/");
         expect(request.getPathInfo()).andReturn(null);
         replay(request);
@@ -180,8 +171,6 @@
         //ensure at least one chain is defined:
         resolver.getFilterChainManager().addToChain("/resource/book", "authcBasic");
 
-        expect(request.getAttribute(WebUtils.INCLUDE_CONTEXT_PATH_ATTRIBUTE)).andReturn(null).anyTimes();
-        expect(request.getContextPath()).andReturn("");
         expect(request.getServletPath()).andReturn("");
         expect(request.getPathInfo()).andReturn("/resource/book");
         replay(request);
@@ -203,8 +192,6 @@
         //ensure at least one chain is defined:
         resolver.getFilterChainManager().addToChain("/", "authcBasic");
 
-        expect(request.getAttribute(WebUtils.INCLUDE_CONTEXT_PATH_ATTRIBUTE)).andReturn(null).anyTimes();
-        expect(request.getContextPath()).andReturn("");
         expect(request.getServletPath()).andReturn("/");
         expect(request.getPathInfo()).andReturn(null);
         replay(request);
@@ -226,8 +213,6 @@
         //ensure at least one chain is defined:
         resolver.getFilterChainManager().addToChain("/resource/book", "authcBasic");
 
-        expect(request.getAttribute(WebUtils.INCLUDE_CONTEXT_PATH_ATTRIBUTE)).andReturn(null).anyTimes();
-        expect(request.getContextPath()).andReturn("");
         expect(request.getServletPath()).andReturn("");
         expect(request.getPathInfo()).andReturn("/resource/book");
         replay(request);
@@ -249,8 +234,6 @@
         //ensure at least one chain is defined:
         resolver.getFilterChainManager().addToChain("/resource/book", "authcBasic");
 
-        expect(request.getAttribute(WebUtils.INCLUDE_CONTEXT_PATH_ATTRIBUTE)).andReturn(null).anyTimes();
-        expect(request.getContextPath()).andReturn("");
         expect(request.getServletPath()).andReturn("");
         expect(request.getPathInfo()).andReturn("/resource/book//");
         replay(request);