Author: mgrigorov
Date: Sun Mar 20 17:43:21 2011
New Revision: 1083519

URL: http://svn.apache.org/viewvc?rev=1083519&view=rev
Log:
WICKET-3544 Race condition in WicketFilter startup with following 
StringIndexOutOfBoundsException


Modified:
    
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/protocol/http/WicketFilter.java
    
wicket/trunk/wicket-core/src/test/java/org/apache/wicket/protocol/http/WicketFilterTest.java

Modified: 
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/protocol/http/WicketFilter.java
URL: 
http://svn.apache.org/viewvc/wicket/trunk/wicket-core/src/main/java/org/apache/wicket/protocol/http/WicketFilter.java?rev=1083519&r1=1083518&r2=1083519&view=diff
==============================================================================
--- 
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/protocol/http/WicketFilter.java
 (original)
+++ 
wicket/trunk/wicket-core/src/main/java/org/apache/wicket/protocol/http/WicketFilter.java
 Sun Mar 20 17:43:21 2011
@@ -494,10 +494,13 @@ public class WicketFilter implements Fil
                // We only need to determine it once. It'll not change.
                if (filterPathLength == -1)
                {
-                       filterPathLength = filterPath.length();
                        if (filterPath.endsWith("/"))
                        {
-                               filterPathLength -= 1;
+                               filterPathLength = filterPath.length() - 1;
+                       }
+                       else
+                       {
+                               filterPathLength = filterPath.length();
                        }
                }
 

Modified: 
wicket/trunk/wicket-core/src/test/java/org/apache/wicket/protocol/http/WicketFilterTest.java
URL: 
http://svn.apache.org/viewvc/wicket/trunk/wicket-core/src/test/java/org/apache/wicket/protocol/http/WicketFilterTest.java?rev=1083519&r1=1083518&r2=1083519&view=diff
==============================================================================
--- 
wicket/trunk/wicket-core/src/test/java/org/apache/wicket/protocol/http/WicketFilterTest.java
 (original)
+++ 
wicket/trunk/wicket-core/src/test/java/org/apache/wicket/protocol/http/WicketFilterTest.java
 Sun Mar 20 17:43:21 2011
@@ -28,6 +28,9 @@ import java.util.HashMap;
 import java.util.Locale;
 import java.util.Map;
 import java.util.TimeZone;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
 
 import javax.servlet.FilterChain;
 import javax.servlet.FilterConfig;
@@ -214,4 +217,88 @@ public class WicketFilterTest extends Te
                filter.setFilterPath("");
                assertNull("", filter.checkIfRedirectRequired("/", ""));
        }
+
+       private static class CheckRedirectWorker implements Runnable
+       {
+               private final WicketFilter filter;
+               private final CountDownLatch startLatch;
+               private final CountDownLatch finishLatch;
+               private final AtomicInteger successCount;
+
+               public CheckRedirectWorker(WicketFilter filter, CountDownLatch 
startLatch,
+                       CountDownLatch finishLatch, AtomicInteger successCount)
+               {
+                       this.filter = filter;
+                       this.startLatch = startLatch;
+                       this.finishLatch = finishLatch;
+                       this.successCount = successCount;
+               }
+
+               public void run()
+               {
+                       try
+                       {
+                               try
+                               {
+                                       startLatch.await(2, TimeUnit.SECONDS);
+                               }
+                               catch (InterruptedException e)
+                               {
+                                       fail();
+                               }
+                               assertEquals("/filter/", 
filter.checkIfRedirectRequired("/filter", ""));
+                               successCount.incrementAndGet();
+                       }
+                       finally
+                       {
+                               finishLatch.countDown();
+                       }
+               }
+       }
+
+       /**
+        * Starts {@code threadCount} threads which try to check whether a 
redirect is required and
+        * initialize {@link WicketFilter#filterPathLength}
+        * 
+        * @param threadCount
+        *            the number of simultaneous threads
+        */
+       private void testParallelCheckRedirect(int threadCount)
+       {
+               WicketFilter filter = new WicketFilter();
+               filter.setFilterPath("filter/");
+               AtomicInteger successCount = new AtomicInteger(0);
+               CountDownLatch startLatch = new CountDownLatch(1);
+               CountDownLatch finishLatch = new CountDownLatch(threadCount);
+               for (int i = 0; i < threadCount; i++)
+               {
+                       new Thread(new CheckRedirectWorker(filter, startLatch, 
finishLatch, successCount)).start();
+               }
+               startLatch.countDown();
+               try
+               {
+                       finishLatch.await(2, TimeUnit.SECONDS);
+               }
+               catch (InterruptedException e)
+               {
+                       fail();
+               }
+               assertEquals("all threads finished", 0, finishLatch.getCount());
+               assertEquals("all redirects correct", threadCount, 
successCount.get());
+       }
+
+       /**
+        * <a 
href="https://issues.apache.org/jira/browse/WICKET-3544";>WICKET-3544</a>
+        * <p>
+        * Runs 1000 times 8 simultaneous threads which try to initialize 
WicketFilter#filterPathLength
+        */
+       public void testRepeatedParallelCheckRedirect()
+       {
+               int threadCount = 8;
+               int repeatCount = 1000;
+               for (int i = 0; i < repeatCount; i++)
+               {
+                       testParallelCheckRedirect(threadCount);
+               }
+       }
 }


Reply via email to