IGNITE-2710: Proper invalidation of session within a request. - Fixes #530.
Signed-off-by: shtykh_roman <[email protected]> Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/79ae76ce Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/79ae76ce Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/79ae76ce Branch: refs/heads/ignite-1786 Commit: 79ae76cef10e32bc3336cd2e1d00b3348e5f7655 Parents: a9a995e Author: shtykh_roman <[email protected]> Authored: Mon Mar 7 10:50:01 2016 +0900 Committer: shtykh_roman <[email protected]> Committed: Mon Mar 7 10:50:01 2016 +0900 ---------------------------------------------------------------------- .../ignite/cache/websession/WebSession.java | 52 +++++++- .../cache/websession/WebSessionFilter.java | 21 +++- .../IgniteWebSessionSelfTestSuite.java | 5 + .../internal/websession/WebSessionSelfTest.java | 124 ++++++++++++++++++- 4 files changed, 194 insertions(+), 8 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/79ae76ce/modules/web/src/main/java/org/apache/ignite/cache/websession/WebSession.java ---------------------------------------------------------------------- diff --git a/modules/web/src/main/java/org/apache/ignite/cache/websession/WebSession.java b/modules/web/src/main/java/org/apache/ignite/cache/websession/WebSession.java index 496600a..7441a1a 100644 --- a/modules/web/src/main/java/org/apache/ignite/cache/websession/WebSession.java +++ b/modules/web/src/main/java/org/apache/ignite/cache/websession/WebSession.java @@ -45,6 +45,9 @@ class WebSession implements HttpSession, Externalizable { /** */ private static final long serialVersionUID = 0L; + /** Flag indicating if the session is valid. */ + private volatile transient boolean isValid = true; + /** Empty session context. */ private static final HttpSessionContext EMPTY_SES_CTX = new HttpSessionContext() { @Nullable @Override public HttpSession getSession(String id) { @@ -86,6 +89,9 @@ class WebSession implements HttpSession, Externalizable { /** Updates list. */ private transient Collection<T2<String, Object>> updates; + /** Genuine http session. */ + private transient HttpSession genuineSession; + /** * Required by {@link Externalizable}. */ @@ -114,6 +120,8 @@ class WebSession implements HttpSession, Externalizable { attrs.put(name, ses.getAttribute(name)); } + + genuineSession = ses; } /** @@ -152,6 +160,15 @@ class WebSession implements HttpSession, Externalizable { } /** + * Checks if the session is valid. + * + * @return True is valid, otherwise false. + */ + protected boolean isValid() { + return this.isValid; + } + + /** * Resets updates list. */ public void resetUpdates() { @@ -181,11 +198,17 @@ class WebSession implements HttpSession, Externalizable { /** {@inheritDoc} */ @Override public long getCreationTime() { + if (!isValid) + throw new IllegalStateException("Call on invalidated session!"); + return createTime; } /** {@inheritDoc} */ @Override public long getLastAccessedTime() { + if (!isValid) + throw new IllegalStateException("Call on invalidated session!"); + return accessTime; } @@ -201,26 +224,38 @@ class WebSession implements HttpSession, Externalizable { /** {@inheritDoc} */ @Override public Object getAttribute(String name) { + if (!isValid) + throw new IllegalStateException("Call on invalidated session!"); + return attrs.get(name); } /** {@inheritDoc} */ @Override public Object getValue(String name) { - return attrs.get(name); + return getAttribute(name); } /** {@inheritDoc} */ @Override public Enumeration<String> getAttributeNames() { + if (!isValid) + throw new IllegalStateException("Call on invalidated session!"); + return Collections.enumeration(attrs.keySet()); } /** {@inheritDoc} */ @Override public String[] getValueNames() { + if (!isValid) + throw new IllegalStateException("Call on invalidated session!"); + return attrs.keySet().toArray(new String[attrs.size()]); } /** {@inheritDoc} */ @Override public void setAttribute(String name, Object val) { + if (!isValid) + throw new IllegalStateException("Call on invalidated session!"); + attrs.put(name, val); if (updates != null) @@ -234,6 +269,9 @@ class WebSession implements HttpSession, Externalizable { /** {@inheritDoc} */ @Override public void removeAttribute(String name) { + if (!isValid) + throw new IllegalStateException("Call on invalidated session!"); + attrs.remove(name); if (updates != null) @@ -247,11 +285,18 @@ class WebSession implements HttpSession, Externalizable { /** {@inheritDoc} */ @Override public void invalidate() { + if (!isValid) + throw new IllegalStateException("Call on invalidated session!"); + attrs.clear(); updates = null; lsnr.destroySession(id); + + genuineSession.invalidate(); + + isValid = false; } /** @@ -263,6 +308,9 @@ class WebSession implements HttpSession, Externalizable { /** {@inheritDoc} */ @Override public boolean isNew() { + if (!isValid) + throw new IllegalStateException("Call on invalidated session!"); + return isNew; } @@ -293,4 +341,4 @@ class WebSession implements HttpSession, Externalizable { @Override public String toString() { return S.toString(WebSession.class, this); } -} \ No newline at end of file +} http://git-wip-us.apache.org/repos/asf/ignite/blob/79ae76ce/modules/web/src/main/java/org/apache/ignite/cache/websession/WebSessionFilter.java ---------------------------------------------------------------------- diff --git a/modules/web/src/main/java/org/apache/ignite/cache/websession/WebSessionFilter.java b/modules/web/src/main/java/org/apache/ignite/cache/websession/WebSessionFilter.java index 4a84931..6e6be33 100644 --- a/modules/web/src/main/java/org/apache/ignite/cache/websession/WebSessionFilter.java +++ b/modules/web/src/main/java/org/apache/ignite/cache/websession/WebSessionFilter.java @@ -328,7 +328,7 @@ public class WebSessionFilter implements Filter { * @param chain Filter chain. * @return Session ID. * @throws IOException In case of I/O error. - * @throws ServletException In case oif servlet error. + * @throws ServletException In case of servlet error. * @throws CacheException In case of other error. */ private String doFilter0(HttpServletRequest httpReq, ServletResponse res, FilterChain chain) throws IOException, @@ -476,9 +476,9 @@ public class WebSessionFilter implements Filter { /** * Request wrapper. */ - private static class RequestWrapper extends HttpServletRequestWrapper { + private class RequestWrapper extends HttpServletRequestWrapper { /** Session. */ - private final WebSession ses; + private volatile WebSession ses; /** * @param req Request. @@ -494,12 +494,23 @@ public class WebSessionFilter implements Filter { /** {@inheritDoc} */ @Override public HttpSession getSession(boolean create) { + if (!ses.isValid()) { + if (create) { + this.ses = createSession((HttpServletRequest)getRequest()); + this.ses.servletContext(ctx); + this.ses.listener(lsnr); + this.ses.resetUpdates(); + } + else + return null; + } + return ses; } /** {@inheritDoc} */ @Override public HttpSession getSession() { - return ses; + return getSession(true); } } -} \ No newline at end of file +} http://git-wip-us.apache.org/repos/asf/ignite/blob/79ae76ce/modules/web/src/test/java/org/apache/ignite/internal/websession/IgniteWebSessionSelfTestSuite.java ---------------------------------------------------------------------- diff --git a/modules/web/src/test/java/org/apache/ignite/internal/websession/IgniteWebSessionSelfTestSuite.java b/modules/web/src/test/java/org/apache/ignite/internal/websession/IgniteWebSessionSelfTestSuite.java index 5c4d736..c69b019 100644 --- a/modules/web/src/test/java/org/apache/ignite/internal/websession/IgniteWebSessionSelfTestSuite.java +++ b/modules/web/src/test/java/org/apache/ignite/internal/websession/IgniteWebSessionSelfTestSuite.java @@ -57,6 +57,11 @@ public class IgniteWebSessionSelfTestSuite extends TestSuite { @Override public void testRestarts() throws Exception { fail("https://issues.apache.org/jira/browse/IGNITE-810"); } + + /** {@inheritDoc} */ + @Override public void testInvalidatedSession() throws Exception { + fail("https://issues.apache.org/jira/browse/IGNITE-810"); + } } /** http://git-wip-us.apache.org/repos/asf/ignite/blob/79ae76ce/modules/web/src/test/java/org/apache/ignite/internal/websession/WebSessionSelfTest.java ---------------------------------------------------------------------- diff --git a/modules/web/src/test/java/org/apache/ignite/internal/websession/WebSessionSelfTest.java b/modules/web/src/test/java/org/apache/ignite/internal/websession/WebSessionSelfTest.java index 7a321d6..e2fda37 100644 --- a/modules/web/src/test/java/org/apache/ignite/internal/websession/WebSessionSelfTest.java +++ b/modules/web/src/test/java/org/apache/ignite/internal/websession/WebSessionSelfTest.java @@ -24,6 +24,8 @@ import java.net.URL; import java.net.URLConnection; import java.util.Random; import java.util.concurrent.Callable; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReferenceArray; @@ -32,11 +34,14 @@ import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; +import org.apache.ignite.Ignite; import org.apache.ignite.IgniteCache; +import org.apache.ignite.events.Event; import org.apache.ignite.internal.IgniteInternalFuture; import org.apache.ignite.internal.util.typedef.G; import org.apache.ignite.internal.util.typedef.X; import org.apache.ignite.internal.util.typedef.internal.U; +import org.apache.ignite.lang.IgnitePredicate; import org.apache.ignite.testframework.GridTestUtils; import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; import org.eclipse.jetty.server.Server; @@ -44,6 +49,8 @@ import org.eclipse.jetty.servlet.ServletHolder; import org.eclipse.jetty.webapp.WebAppContext; import org.jetbrains.annotations.Nullable; +import static org.apache.ignite.events.EventType.EVT_CACHE_OBJECT_PUT; + /** * Tests the correctness of web sessions caching functionality. */ @@ -110,6 +117,91 @@ public class WebSessionSelfTest extends GridCommonAbstractTest { } /** + * Tests invalidated sessions. + * + * @throws Exception Exception If failed. + */ + public void testInvalidatedSession() throws Exception { + String invalidatedSesId; + Server srv = null; + + try { + srv = startServer(TEST_JETTY_PORT, "/modules/core/src/test/config/websession/example-cache.xml", + null, new InvalidatedSessionServlet()); + + Ignite ignite = G.ignite(); + + URLConnection conn = new URL("http://localhost:" + TEST_JETTY_PORT + "/ignitetest/invalidated").openConnection(); + + conn.connect(); + + try (BufferedReader rdr = new BufferedReader(new InputStreamReader(conn.getInputStream()))) { + + // checks if the old session object is invalidated. + invalidatedSesId = rdr.readLine(); + + assertNotNull(invalidatedSesId); + + IgniteCache<String, HttpSession> cache = ignite.cache(getCacheName()); + + assertNotNull(cache); + + HttpSession invalidatedSes = cache.get(invalidatedSesId); + + assertNull(invalidatedSes); + + // requests to subsequent getSession() returns null. + String ses = rdr.readLine(); + + assertEquals("null", ses); + } + + // put and update. + final CountDownLatch latch = new CountDownLatch(2); + + final IgnitePredicate<Event> putLsnr = new IgnitePredicate<Event>() { + @Override public boolean apply(Event evt) { + assert evt != null; + + latch.countDown(); + + return true; + } + }; + + ignite.events().localListen(putLsnr, EVT_CACHE_OBJECT_PUT); + + // new request that creates a new session. + conn = new URL("http://localhost:" + TEST_JETTY_PORT + "/ignitetest/valid").openConnection(); + + conn.addRequestProperty("Cookie", "JSESSIONID=" + invalidatedSesId); + + conn.connect(); + + try (BufferedReader rdr = new BufferedReader(new InputStreamReader(conn.getInputStream()))) { + String sesId = rdr.readLine(); + + assertFalse(sesId.equals("null")); + + assertTrue(latch.await(10, TimeUnit.SECONDS)); + + IgniteCache<String, HttpSession> cache = ignite.cache(getCacheName()); + + assertNotNull(cache); + + HttpSession ses = cache.get(sesId); + + assertNotNull(ses); + + assertEquals("val10", ses.getAttribute("key10")); + } + } + finally { + stopServer(srv); + } + } + + /** * @throws Exception If failed. */ public void testRestarts() throws Exception { @@ -296,6 +388,36 @@ public class WebSessionSelfTest extends GridCommonAbstractTest { } /** + * Test for invalidated sessions. + */ + private static class InvalidatedSessionServlet extends HttpServlet { + /** {@inheritDoc} */ + @Override protected void doGet(HttpServletRequest req, HttpServletResponse res) + throws ServletException, IOException { + HttpSession ses = req.getSession(); + + assert ses != null; + + if (req.getPathInfo().equals("/invalidated")) { + X.println(">>>", "Session to invalidate with id: " + ses.getId(), ">>>"); + + ses.invalidate(); + + res.getWriter().println(ses.getId()); + } + else if (req.getPathInfo().equals("/valid")) { + X.println(">>>", "Created session: " + ses.getId(), ">>>"); + + ses.setAttribute("key10", "val10"); + } + + res.getWriter().println((req.getSession(false) == null) ? "null" : ses.getId()); + + res.getWriter().flush(); + } + } + + /** * Servlet for restarts test. */ private static class RestartsTestServlet extends HttpServlet { @@ -330,4 +452,4 @@ public class WebSessionSelfTest extends GridCommonAbstractTest { res.getWriter().flush(); } } -} \ No newline at end of file +}
