From 0834ad259cdf483795049b54409e610a4fd36944 Mon Sep 17 00:00:00 2001 From: Jan Bartel Date: Mon, 11 Mar 2013 19:30:52 +1100 Subject: [PATCH] 402706 HttpSession.setMaxInactiveInterval(int) does not change JDBCSession expiry --- .../server/session/JDBCSessionIdManager.java | 43 +++++- .../server/session/JDBCSessionManager.java | 59 ++++++- .../ModifyMaxInactiveIntervalTest.java | 145 ++++++++++++++++++ 3 files changed, 235 insertions(+), 12 deletions(-) create mode 100644 tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ModifyMaxInactiveIntervalTest.java diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/JDBCSessionIdManager.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/JDBCSessionIdManager.java index a64c026e339..44f5620e43f 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/JDBCSessionIdManager.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/JDBCSessionIdManager.java @@ -62,6 +62,7 @@ import org.eclipse.jetty.util.log.Logger; public class JDBCSessionIdManager extends AbstractSessionIdManager { final static Logger LOG = SessionHandler.LOG; + public final static int MAX_INTERVAL_NOT_SET = -999; protected final HashSet _sessionIds = new HashSet(); protected Server _server; @@ -629,6 +630,9 @@ public class JDBCSessionIdManager extends AbstractSessionIdManager * Set up the tables in the database * @throws SQLException */ + /** + * @throws SQLException + */ private void prepareTables() throws SQLException { @@ -671,9 +675,38 @@ public class JDBCSessionIdManager extends AbstractSessionIdManager _createSessionTable = "create table "+_sessionTable+" ("+_sessionTableRowId+" varchar(120), sessionId varchar(120), "+ " contextPath varchar(60), virtualHost varchar(60), lastNode varchar(60), accessTime "+longType+", "+ " lastAccessTime "+longType+", createTime "+longType+", cookieTime "+longType+", "+ - " lastSavedTime "+longType+", expiryTime "+longType+", map "+blobType+", primary key("+_sessionTableRowId+"))"; + " lastSavedTime "+longType+", expiryTime "+longType+", maxInterval "+longType+", map "+blobType+", primary key("+_sessionTableRowId+"))"; connection.createStatement().executeUpdate(_createSessionTable); } + else + { + //session table exists, check it has maxinterval column + ResultSet colResult = null; + try + { + colResult = metaData.getColumns(null, null,_dbAdaptor.convertIdentifier(_sessionTable), _dbAdaptor.convertIdentifier("maxInterval")); + } + catch (SQLException s) + { + LOG.warn("Problem checking if "+_sessionTable+" table contains maxInterval column. Ensure table contains column definition: \"maxInterval long not null default -999\""); + throw s; + } + + if (!colResult.next()) + { + try + { + //add the maxinterval column + String longType = _dbAdaptor.getLongType(); + connection.createStatement().executeUpdate("alter table "+_sessionTable+" add maxInterval "+longType+" not null default "+MAX_INTERVAL_NOT_SET); + } + catch (SQLException s) + { + LOG.warn("Problem adding maxInterval column. Ensure table contains column definition: \"maxInterval long not null default -999\""); + throw s; + } + } + } //make some indexes on the JettySessions table String index1 = "idx_"+_sessionTable+"_expiry"; @@ -701,20 +734,20 @@ public class JDBCSessionIdManager extends AbstractSessionIdManager //set up some strings representing the statements for session manipulation _insertSession = "insert into "+_sessionTable+ - " ("+_sessionTableRowId+", sessionId, contextPath, virtualHost, lastNode, accessTime, lastAccessTime, createTime, cookieTime, lastSavedTime, expiryTime, map) "+ - " values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; + " ("+_sessionTableRowId+", sessionId, contextPath, virtualHost, lastNode, accessTime, lastAccessTime, createTime, cookieTime, lastSavedTime, expiryTime, maxInterval, map) "+ + " values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; _deleteSession = "delete from "+_sessionTable+ " where "+_sessionTableRowId+" = ?"; _updateSession = "update "+_sessionTable+ - " set sessionId = ?, lastNode = ?, accessTime = ?, lastAccessTime = ?, lastSavedTime = ?, expiryTime = ?, map = ? where "+_sessionTableRowId+" = ?"; + " set sessionId = ?, lastNode = ?, accessTime = ?, lastAccessTime = ?, lastSavedTime = ?, expiryTime = ?, maxInterval = ?, map = ? where "+_sessionTableRowId+" = ?"; _updateSessionNode = "update "+_sessionTable+ " set lastNode = ? where "+_sessionTableRowId+" = ?"; _updateSessionAccessTime = "update "+_sessionTable+ - " set lastNode = ?, accessTime = ?, lastAccessTime = ?, lastSavedTime = ?, expiryTime = ? where "+_sessionTableRowId+" = ?"; + " set lastNode = ?, accessTime = ?, lastAccessTime = ?, lastSavedTime = ?, expiryTime = ?, maxInterval = ? where "+_sessionTableRowId+" = ?"; } 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 0111118e938..fd91a4c65cb 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 @@ -160,10 +160,12 @@ public class JDBCSessionManager extends AbstractSessionManager * @param created * @param accessed */ - protected Session (String sessionId, String rowId, long created, long accessed) + protected Session (String sessionId, String rowId, long created, long accessed, long maxInterval) { super(JDBCSessionManager.this, created, accessed, sessionId); _rowId = rowId; + super.setMaxInactiveInterval((int)maxInterval); //restore the session's previous inactivity interval setting + _expiryTime = (maxInterval <= 0 ? 0 : (System.currentTimeMillis() + maxInterval*1000L)); } @@ -279,6 +281,33 @@ public class JDBCSessionManager extends AbstractSessionManager } } + + + + + /** + * Change the max idle time for this session. This recalculates the expiry time. + * @see org.eclipse.jetty.server.session.AbstractSession#setMaxInactiveInterval(int) + */ + @Override + public void setMaxInactiveInterval(int secs) + { + synchronized (this) + { + super.setMaxInactiveInterval(secs); + int maxInterval=getMaxInactiveInterval(); + _expiryTime = (maxInterval <= 0 ? 0 : (System.currentTimeMillis() + maxInterval*1000L)); + //force the session to be written out right now + try + { + updateSessionAccessTime(this); + } + catch (Exception e) + { + LOG.warn("Problem saving changed max idle time for session "+ this, e); + } + } + } /** @@ -346,7 +375,7 @@ public class JDBCSessionManager extends AbstractSessionManager return "Session rowId="+_rowId+",id="+getId()+",lastNode="+_lastNode+ ",created="+getCreationTime()+",accessed="+getAccessed()+ ",lastAccessed="+getLastAccessedTime()+",cookieSet="+_cookieSet+ - ",lastSaved="+_lastSaved+",expiry="+_expiryTime; + ",maxInterval="+getMaxInactiveInterval()+",lastSaved="+_lastSaved+",expiry="+_expiryTime; } } @@ -842,6 +871,9 @@ public class JDBCSessionManager extends AbstractSessionManager final AtomicReference _exception = new AtomicReference(); Runnable load = new Runnable() { + /** + * @see java.lang.Runnable#run() + */ @SuppressWarnings("unchecked") public void run() { @@ -855,7 +887,15 @@ public class JDBCSessionManager extends AbstractSessionManager ResultSet result = statement.executeQuery(); if (result.next()) { - session = new Session(id, result.getString(_jdbcSessionIdMgr._sessionTableRowId), result.getLong("createTime"), result.getLong("accessTime")); + long maxInterval = result.getLong("maxInterval"); + if (maxInterval == JDBCSessionIdManager.MAX_INTERVAL_NOT_SET) + { + maxInterval = getMaxInactiveInterval(); //if value not saved for maxInactiveInterval, use current value from sessionmanager + } + session = new Session(id, result.getString(_jdbcSessionIdMgr._sessionTableRowId), + result.getLong("createTime"), + result.getLong("accessTime"), + maxInterval); session.setCookieSet(result.getLong("cookieTime")); session.setLastAccessedTime(result.getLong("lastAccessTime")); session.setLastNode(result.getString("lastNode")); @@ -939,6 +979,7 @@ public class JDBCSessionManager extends AbstractSessionManager statement.setLong(9, session.getCookieSet());//time cookie was set statement.setLong(10, now); //last saved time statement.setLong(11, session.getExpiryTime()); + statement.setLong(12, session.getMaxInactiveInterval()); ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); @@ -946,7 +987,8 @@ public class JDBCSessionManager extends AbstractSessionManager byte[] bytes = baos.toByteArray(); ByteArrayInputStream bais = new ByteArrayInputStream(bytes); - statement.setBinaryStream(12, bais, bytes.length);//attribute map as blob + statement.setBinaryStream(13, bais, bytes.length);//attribute map as blob + statement.executeUpdate(); session.setRowId(rowId); //set it on the in-memory data as well as in db @@ -989,6 +1031,7 @@ public class JDBCSessionManager extends AbstractSessionManager statement.setLong(4, data.getLastAccessedTime()); //lastAccessTime statement.setLong(5, now); //last saved time statement.setLong(6, data.getExpiryTime()); + statement.setLong(7, data.getMaxInactiveInterval()); ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); @@ -996,8 +1039,8 @@ public class JDBCSessionManager extends AbstractSessionManager byte[] bytes = baos.toByteArray(); ByteArrayInputStream bais = new ByteArrayInputStream(bytes); - statement.setBinaryStream(7, bais, bytes.length);//attribute map as blob - statement.setString(8, data.getRowId()); //rowId + statement.setBinaryStream(8, bais, bytes.length);//attribute map as blob + statement.setString(9, data.getRowId()); //rowId statement.executeUpdate(); data.setLastSaved(now); @@ -1063,7 +1106,9 @@ public class JDBCSessionManager extends AbstractSessionManager statement.setLong(3, data.getLastAccessedTime()); statement.setLong(4, now); statement.setLong(5, data.getExpiryTime()); - statement.setString(6, data.getRowId()); + statement.setLong(6, data.getMaxInactiveInterval()); + statement.setString(7, data.getRowId()); + statement.executeUpdate(); data.setLastSaved(now); statement.close(); diff --git a/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ModifyMaxInactiveIntervalTest.java b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ModifyMaxInactiveIntervalTest.java new file mode 100644 index 00000000000..647109775cb --- /dev/null +++ b/tests/test-sessions/test-jdbc-sessions/src/test/java/org/eclipse/jetty/server/session/ModifyMaxInactiveIntervalTest.java @@ -0,0 +1,145 @@ +// +// ======================================================================== +// Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +// + +package org.eclipse.jetty.server.session; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +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.junit.Test; + + +/** + * ModifyMaxInactiveIntervalTest + * + * + * + */ +public class ModifyMaxInactiveIntervalTest +{ + + public static int inactive = 4; + public static int newMaxInactive = 20; + public static int scavenge = 1; + + @Test + public void testSessionExpiryAfterModifiedMaxInactiveInterval() throws Exception + { + AbstractTestServer server = new JdbcTestServer(0,inactive,scavenge); + + ServletContextHandler ctxA = server.addContext("/mod"); + ctxA.addServlet(TestModServlet.class, "/test"); + + server.start(); + int port=server.getPort(); + try + { + HttpClient client = new HttpClient(); + client.start(); + try + { + // Perform a request to create a session + + ContentResponse response = client.GET("http://localhost:" + port + "/mod/test?action=create"); + + assertEquals(HttpServletResponse.SC_OK,response.getStatus()); + String sessionCookie = response.getHeaders().getStringField("Set-Cookie"); + assertTrue(sessionCookie != null); + // Mangle the cookie, replacing Path with $Path, etc. + sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path="); + + //do another request to change the maxinactive interval + Request request = client.newRequest("http://localhost:" + port + "/mod/test?action=change&val="+newMaxInactive); + request.header("Cookie", sessionCookie); + response = request.send(); + + assertEquals(HttpServletResponse.SC_OK,response.getStatus()); + + //wait for longer than the old inactive interval + Thread.currentThread().sleep(10*1000L); + + //do another request using the cookie to ensure the session is still there + + request= client.newRequest("http://localhost:" + port + "/mod/test?action=test"); + request.header("Cookie", sessionCookie); + response = request.send(); + assertEquals(HttpServletResponse.SC_OK,response.getStatus()); + } + finally + { + client.stop(); + } + } + finally + { + server.stop(); + } + } + + public static class TestModServlet extends HttpServlet + { + @Override + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + { + String action = request.getParameter("action"); + + if ("create".equals(action)) + { + HttpSession session = request.getSession(true); + return; + } + + if ("change".equals(action)) + { + HttpSession session = request.getSession(false); + if (session == null) + throw new ServletException("Session is null for action=change"); + + String tmp = request.getParameter("val"); + int interval = -1; + interval = (tmp==null?-1:Integer.parseInt(tmp)); + + if (interval > 0) + session.setMaxInactiveInterval(interval); + return; + } + + if ("test".equals(action)) + { + HttpSession session = request.getSession(false); + if (session == null) + throw new ServletException("Session does not exist"); + assertEquals(ModifyMaxInactiveIntervalTest.newMaxInactive, session.getMaxInactiveInterval()); + return; + } + } + } + +}