From f544d6e7010753a0b23f6aa923b81d8962358807 Mon Sep 17 00:00:00 2001 From: Jan Bartel Date: Fri, 3 May 2013 18:27:51 +1000 Subject: [PATCH] 405422 Implement servlet3.1 spec sections 4.4.3 and 8.1.4 for new HttpSessionIdListener class --- .../annotations/WebListenerAnnotation.java | 4 ++- .../jetty/nosql/NoSqlSessionManager.java | 1 + .../jetty/server/session/AbstractSession.java | 4 +-- .../session/AbstractSessionManager.java | 28 +++++++++++++++++ .../server/session/HashSessionManager.java | 2 ++ .../server/session/JDBCSessionManager.java | 2 ++ .../eclipse/jetty/webapp/WebAppContext.java | 7 +++-- .../session/AbstractSessionRenewTest.java | 31 ++++++++++++++++++- 8 files changed, 73 insertions(+), 6 deletions(-) diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebListenerAnnotation.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebListenerAnnotation.java index b82fd1104ab..c55bca29c76 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebListenerAnnotation.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebListenerAnnotation.java @@ -23,6 +23,7 @@ import javax.servlet.ServletContextListener; import javax.servlet.ServletRequestAttributeListener; import javax.servlet.ServletRequestListener; import javax.servlet.http.HttpSessionAttributeListener; +import javax.servlet.http.HttpSessionIdListener; import javax.servlet.http.HttpSessionListener; import org.eclipse.jetty.util.log.Log; @@ -78,7 +79,8 @@ public class WebListenerAnnotation extends DiscoveredAnnotation ServletRequestListener.class.isAssignableFrom(clazz) || ServletRequestAttributeListener.class.isAssignableFrom(clazz) || HttpSessionListener.class.isAssignableFrom(clazz) || - HttpSessionAttributeListener.class.isAssignableFrom(clazz)) + HttpSessionAttributeListener.class.isAssignableFrom(clazz) || + HttpSessionIdListener.class.isAssignableFrom(clazz)) { java.util.EventListener listener = (java.util.EventListener)clazz.newInstance(); MetaData metaData = _context.getMetaData(); diff --git a/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/NoSqlSessionManager.java b/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/NoSqlSessionManager.java index e5f0e17fd58..48acc817da1 100644 --- a/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/NoSqlSessionManager.java +++ b/jetty-nosql/src/main/java/org/eclipse/jetty/nosql/NoSqlSessionManager.java @@ -332,6 +332,7 @@ public abstract class NoSqlSessionManager extends AbstractSessionManager impleme __log.warn(e); } } + super.renewSessionId(oldClusterId, oldNodeId, newClusterId, newNodeId); } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSession.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSession.java index 9830df24f2c..9f013221e7d 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSession.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSession.java @@ -51,8 +51,8 @@ public abstract class AbstractSession implements AbstractSessionManager.SessionI { final static Logger LOG = SessionHandler.LOG; public final static String SESSION_KNOWN_ONLY_TO_AUTHENTICATED="org.eclipse.jetty.security.sessionKnownOnlytoAuthenticated"; - private String _clusterId; // ID unique within cluster - private String _nodeId; // ID unique within node + private String _clusterId; // ID without any node (ie "worker") id appended + private String _nodeId; // ID of session with node(ie "worker") id appended private final AbstractSessionManager _manager; private final Map _attributes=new HashMap(); private boolean _idChanged; diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSessionManager.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSessionManager.java index a81453e22f1..2ffddd354f8 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSessionManager.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSessionManager.java @@ -38,6 +38,7 @@ import javax.servlet.http.HttpSessionAttributeListener; import javax.servlet.http.HttpSessionBindingEvent; import javax.servlet.http.HttpSessionContext; import javax.servlet.http.HttpSessionEvent; +import javax.servlet.http.HttpSessionIdListener; import javax.servlet.http.HttpSessionListener; import org.eclipse.jetty.http.HttpCookie; @@ -107,6 +108,7 @@ public abstract class AbstractSessionManager extends AbstractLifeCycle implement protected final List _sessionAttributeListeners = new CopyOnWriteArrayList(); protected final List _sessionListeners= new CopyOnWriteArrayList(); + protected final List _sessionIdListeners = new CopyOnWriteArrayList(); protected ClassLoader _loader; protected ContextHandler.Context _context; @@ -191,6 +193,8 @@ public abstract class AbstractSessionManager extends AbstractLifeCycle implement _sessionAttributeListeners.add((HttpSessionAttributeListener)listener); if (listener instanceof HttpSessionListener) _sessionListeners.add((HttpSessionListener)listener); + if (listener instanceof HttpSessionIdListener) + _sessionIdListeners.add((HttpSessionIdListener)listener); } /* ------------------------------------------------------------ */ @@ -198,6 +202,7 @@ public abstract class AbstractSessionManager extends AbstractLifeCycle implement { _sessionAttributeListeners.clear(); _sessionListeners.clear(); + _sessionIdListeners.clear(); } /* ------------------------------------------------------------ */ @@ -990,6 +995,29 @@ public abstract class AbstractSessionManager extends AbstractLifeCycle implement { _checkingRemoteSessionIdEncoding=remote; } + + + /* ------------------------------------------------------------ */ + /** + * Tell the HttpSessionIdListeners the id changed. + * NOTE: this method must be called LAST in subclass overrides, after the session has been updated + * with the new id. + * @see org.eclipse.jetty.server.SessionManager#renewSessionId(java.lang.String, java.lang.String, java.lang.String, java.lang.String) + */ + @Override + public void renewSessionId(String oldClusterId, String oldNodeId, String newClusterId, String newNodeId) + { + if (!_sessionIdListeners.isEmpty()) + { + AbstractSession session = getSession(newClusterId); + HttpSessionEvent event = new HttpSessionEvent(session); + for (HttpSessionIdListener l:_sessionIdListeners) + { + l.sessionIdChanged(event, oldClusterId); + } + } + + } /* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */ diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/HashSessionManager.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/HashSessionManager.java index 1954894aafe..7acf6e98ac7 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/HashSessionManager.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/HashSessionManager.java @@ -439,6 +439,8 @@ public class HashSessionManager extends AbstractSessionManager session.setNodeId(newNodeId); session.save(); //save updated session: TODO consider only saving file if idled sessions.put(newClusterId, session); + + super.renewSessionId(oldClusterId, oldNodeId, newClusterId, newNodeId); } catch (Exception e) { diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/JDBCSessionManager.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/JDBCSessionManager.java index afe7ae2c0ae..d1a2708f0e1 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/JDBCSessionManager.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/JDBCSessionManager.java @@ -645,6 +645,8 @@ public class JDBCSessionManager extends AbstractSessionManager LOG.warn(e); } } + + super.renewSessionId(oldClusterId, oldNodeId, newClusterId, newNodeId); } diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppContext.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppContext.java index 2489138e491..650c6a0873d 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppContext.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppContext.java @@ -41,6 +41,7 @@ import javax.servlet.ServletSecurityElement; import javax.servlet.http.HttpSessionActivationListener; import javax.servlet.http.HttpSessionAttributeListener; import javax.servlet.http.HttpSessionBindingListener; +import javax.servlet.http.HttpSessionIdListener; import javax.servlet.http.HttpSessionListener; import org.eclipse.jetty.security.ConstraintAware; @@ -1058,7 +1059,8 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL if ((listener instanceof HttpSessionActivationListener) || (listener instanceof HttpSessionAttributeListener) || (listener instanceof HttpSessionBindingListener) - || (listener instanceof HttpSessionListener)) + || (listener instanceof HttpSessionListener) + || (listener instanceof HttpSessionIdListener)) { if (_sessionHandler!=null) _sessionHandler.addEventListener(listener); @@ -1072,7 +1074,8 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL if ((listener instanceof HttpSessionActivationListener) || (listener instanceof HttpSessionAttributeListener) || (listener instanceof HttpSessionBindingListener) - || (listener instanceof HttpSessionListener)) + || (listener instanceof HttpSessionListener) + || (listener instanceof HttpSessionIdListener)) { if (_sessionHandler!=null) _sessionHandler.removeEventListener(listener); diff --git a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionRenewTest.java b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionRenewTest.java index 070ddf1a5c9..34cae2bddd7 100644 --- a/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionRenewTest.java +++ b/tests/test-sessions/test-sessions-common/src/main/java/org/eclipse/jetty/server/session/AbstractSessionRenewTest.java @@ -32,11 +32,14 @@ import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; +import javax.servlet.http.HttpSessionEvent; +import javax.servlet.http.HttpSessionIdListener; import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.client.api.ContentResponse; import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.webapp.WebAppContext; public abstract class AbstractSessionRenewTest @@ -49,8 +52,11 @@ public abstract class AbstractSessionRenewTest String servletMapping = "/server"; int scavengePeriod = 3; AbstractTestServer server = createServer(0, 1, scavengePeriod); - ServletContextHandler context = server.addContext(contextPath); + WebAppContext context = server.addWebAppContext(".", contextPath); context.addServlet(TestServlet.class, servletMapping); + TestHttpSessionIdListener testListener = new TestHttpSessionIdListener(); + context.addEventListener(testListener); + HttpClient client = new HttpClient(); @@ -67,6 +73,7 @@ public abstract class AbstractSessionRenewTest String sessionCookie = response.getHeaders().getStringField("Set-Cookie"); assertTrue(sessionCookie != null); + assertFalse(testListener.isCalled()); //make a request to change the sessionid Request request = client.newRequest("http://localhost:" + port + contextPath + servletMapping + "?action=renew"); @@ -76,6 +83,7 @@ public abstract class AbstractSessionRenewTest String renewSessionCookie = renewResponse.getHeaders().getStringField("Set-Cookie"); assertNotNull(renewSessionCookie); assertNotSame(sessionCookie, renewSessionCookie); + assertTrue(testListener.isCalled()); } finally { @@ -84,9 +92,30 @@ public abstract class AbstractSessionRenewTest } } + + + public static class TestHttpSessionIdListener implements HttpSessionIdListener + { + boolean called = false; + + @Override + public void sessionIdChanged(HttpSessionEvent event, String oldSessionId) + { + assertNotNull(event.getSession()); + assertNotSame(oldSessionId, event.getSession().getId()); + called = true; + } + + public boolean isCalled() + { + return called; + } + } + public static class TestServlet extends HttpServlet { + @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {