394829 Session can not be restored after SessionManager.setIdleSavePeriod has saved the session
This commit is contained in:
parent
597649d4aa
commit
8920fcc128
|
@ -40,7 +40,10 @@ import org.eclipse.jetty.util.log.Logger;
|
|||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** An in-memory implementation of SessionManager.
|
||||
/**
|
||||
* HashSessionManager
|
||||
*
|
||||
* An in-memory implementation of SessionManager.
|
||||
* <p>
|
||||
* This manager supports saving sessions to disk, either periodically or at shutdown.
|
||||
* Sessions can also have their content idle saved to disk to reduce the memory overheads of large idle sessions.
|
||||
|
@ -77,7 +80,7 @@ public class HashSessionManager extends AbstractSessionManager
|
|||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/* (non-Javadoc)
|
||||
/**
|
||||
* @see org.eclipse.jetty.servlet.AbstractSessionManager#doStart()
|
||||
*/
|
||||
@Override
|
||||
|
@ -110,7 +113,7 @@ public class HashSessionManager extends AbstractSessionManager
|
|||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/* (non-Javadoc)
|
||||
/**
|
||||
* @see org.eclipse.jetty.servlet.AbstractSessionManager#doStop()
|
||||
*/
|
||||
@Override
|
||||
|
@ -252,7 +255,7 @@ public class HashSessionManager extends AbstractSessionManager
|
|||
* @param seconds the period in seconds at which a check is made for sessions to be invalidated.
|
||||
*/
|
||||
public void setScavengePeriod(int seconds)
|
||||
{
|
||||
{
|
||||
if (seconds==0)
|
||||
seconds=60;
|
||||
|
||||
|
@ -264,6 +267,7 @@ public class HashSessionManager extends AbstractSessionManager
|
|||
period=1000;
|
||||
|
||||
_scavengePeriodMs=period;
|
||||
|
||||
if (_timer!=null && (period!=old_period || _task==null))
|
||||
{
|
||||
synchronized (this)
|
||||
|
@ -303,25 +307,36 @@ public class HashSessionManager extends AbstractSessionManager
|
|||
|
||||
// For each session
|
||||
long now=System.currentTimeMillis();
|
||||
|
||||
for (Iterator<HashedSession> i=_sessions.values().iterator(); i.hasNext();)
|
||||
{
|
||||
HashedSession session=i.next();
|
||||
long idleTime=session.getMaxInactiveInterval()*1000L;
|
||||
long idleTime=session.getMaxInactiveInterval()*1000L;
|
||||
if (idleTime>0&&session.getAccessed()+idleTime<now)
|
||||
{
|
||||
// Found a stale session, add it to the list
|
||||
session.timeout();
|
||||
try
|
||||
{
|
||||
session.timeout();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
__log.warn("Problem scavenging sessions", e);
|
||||
}
|
||||
}
|
||||
else if (_idleSavePeriodMs>0&&session.getAccessed()+_idleSavePeriodMs<now)
|
||||
else if (_idleSavePeriodMs > 0 && session.getAccessed()+_idleSavePeriodMs < now)
|
||||
{
|
||||
session.idle();
|
||||
try
|
||||
{
|
||||
session.idle();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
__log.warn("Problem idling session "+ session.getId(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
__log.warn("Problem scavenging sessions", t);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
thread.setContextClassLoader(old_loader);
|
||||
|
|
|
@ -100,6 +100,7 @@ public class HashedSession extends AbstractSession
|
|||
|
||||
/* ------------------------------------------------------------ */
|
||||
synchronized void save(boolean reactivate)
|
||||
throws Exception
|
||||
{
|
||||
// Only idle the session if not already idled and no previous save/idle has failed
|
||||
if (!isIdled() && !_saveFailed)
|
||||
|
@ -128,16 +129,13 @@ public class HashedSession extends AbstractSession
|
|||
catch (Exception e)
|
||||
{
|
||||
saveFailed(); // We won't try again for this session
|
||||
|
||||
LOG.warn("Problem saving session " + super.getId(), e);
|
||||
|
||||
if (fos != null)
|
||||
{
|
||||
// Must not leave the file open if the saving failed
|
||||
IO.close(fos);
|
||||
// No point keeping the file if we didn't save the whole session
|
||||
file.delete();
|
||||
_idled=false; // assume problem was before _values.clear();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -181,7 +179,7 @@ public class HashedSession extends AbstractSession
|
|||
access(System.currentTimeMillis());
|
||||
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Deidling " + super.getId());
|
||||
LOG.debug("De-idling " + super.getId());
|
||||
|
||||
FileInputStream fis = null;
|
||||
|
||||
|
@ -203,7 +201,7 @@ public class HashedSession extends AbstractSession
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn("Problem deidling session " + super.getId(), e);
|
||||
LOG.warn("Problem de-idling session " + super.getId(), e);
|
||||
IO.close(fis);
|
||||
invalidate();
|
||||
}
|
||||
|
@ -219,8 +217,10 @@ public class HashedSession extends AbstractSession
|
|||
* it to an idled state.
|
||||
*/
|
||||
public synchronized void idle()
|
||||
throws Exception
|
||||
{
|
||||
save(false);
|
||||
_idled = true;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
|
|
@ -48,7 +48,7 @@ public class HashTestServer extends AbstractTestServer
|
|||
public SessionManager newSessionManager()
|
||||
{
|
||||
HashSessionManager manager = new HashSessionManager();
|
||||
manager.setScavengePeriod((int)TimeUnit.SECONDS.toMillis(_scavengePeriod));
|
||||
manager.setScavengePeriod(_scavengePeriod);
|
||||
return manager;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,217 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 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 static org.junit.Assert.assertNotNull;
|
||||
|
||||
|
||||
import java.io.File;
|
||||
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.ContentExchange;
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.eclipse.jetty.http.HttpMethods;
|
||||
import org.eclipse.jetty.server.SessionManager;
|
||||
import org.eclipse.jetty.server.session.AbstractSessionExpiryTest.TestServlet;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.junit.Test;
|
||||
|
||||
|
||||
/**
|
||||
* IdleSessionTest
|
||||
*
|
||||
* Checks that a session can be idled and de-idled on the next request if it hasn't expired.
|
||||
*
|
||||
*/
|
||||
public class IdleSessionTest
|
||||
{
|
||||
public class IdleHashTestServer extends HashTestServer
|
||||
{
|
||||
private int _idlePeriod;
|
||||
private File _storeDir;
|
||||
|
||||
/**
|
||||
* @param port
|
||||
* @param maxInactivePeriod
|
||||
* @param scavengePeriod
|
||||
* @param idlePeriod
|
||||
*/
|
||||
public IdleHashTestServer(int port, int maxInactivePeriod, int scavengePeriod, int idlePeriod, File storeDir)
|
||||
{
|
||||
super(port, maxInactivePeriod, scavengePeriod);
|
||||
_idlePeriod = idlePeriod;
|
||||
_storeDir = storeDir;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SessionManager newSessionManager()
|
||||
{
|
||||
HashSessionManager manager = (HashSessionManager)super.newSessionManager();
|
||||
manager.setStoreDirectory(_storeDir);
|
||||
manager.setIdleSavePeriod(_idlePeriod);
|
||||
return manager;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
public HashTestServer createServer(int port, int max, int scavenge, int idle, File storeDir)
|
||||
{
|
||||
HashTestServer server = new IdleHashTestServer(port, max, scavenge, idle, storeDir);
|
||||
return server;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void pause (int sec)
|
||||
{
|
||||
try
|
||||
{
|
||||
Thread.sleep(sec * 1000L);
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSessionIdle() throws Exception
|
||||
{
|
||||
String contextPath = "";
|
||||
String servletMapping = "/server";
|
||||
int inactivePeriod = 200;
|
||||
int scavengePeriod = 3;
|
||||
int idlePeriod = 5;
|
||||
|
||||
File storeDir = new File (System.getProperty("java.io.tmpdir"), "idle-test");
|
||||
storeDir.deleteOnExit();
|
||||
|
||||
HashTestServer server1 = createServer(0, inactivePeriod, scavengePeriod, idlePeriod, storeDir);
|
||||
TestServlet servlet = new TestServlet();
|
||||
ServletHolder holder = new ServletHolder(servlet);
|
||||
ServletContextHandler contextHandler = server1.addContext(contextPath);
|
||||
contextHandler.addServlet(holder, servletMapping);
|
||||
server1.start();
|
||||
int port1 = server1.getPort();
|
||||
|
||||
try
|
||||
{
|
||||
HttpClient client = new HttpClient();
|
||||
client.setConnectorType(HttpClient.CONNECTOR_SOCKET);
|
||||
client.start();
|
||||
String url = "http://localhost:" + port1 + contextPath + servletMapping;
|
||||
|
||||
//make a request to set up a session on the server
|
||||
ContentExchange exchange1 = new ContentExchange(true);
|
||||
exchange1.setMethod(HttpMethods.GET);
|
||||
exchange1.setURL(url + "?action=init");
|
||||
client.send(exchange1);
|
||||
exchange1.waitForDone();
|
||||
assertEquals(HttpServletResponse.SC_OK,exchange1.getResponseStatus());
|
||||
String sessionCookie = exchange1.getResponseFields().getStringField("Set-Cookie");
|
||||
assertTrue(sessionCookie != null);
|
||||
// Mangle the cookie, replacing Path with $Path, etc.
|
||||
sessionCookie = sessionCookie.replaceFirst("(\\W)(P|p)ath=", "$1\\$Path=");
|
||||
|
||||
//and wait until the session should be idled out
|
||||
pause(scavengePeriod * 2);
|
||||
|
||||
//check that the file exists
|
||||
checkSessionIdled(storeDir);
|
||||
|
||||
//make another request to de-idle the session
|
||||
ContentExchange exchange2 = new ContentExchange(true);
|
||||
exchange2.setMethod(HttpMethods.GET);
|
||||
exchange2.setURL(url + "?action=test");
|
||||
exchange2.getRequestFields().add("Cookie", sessionCookie);
|
||||
client.send(exchange2);
|
||||
exchange2.waitForDone();
|
||||
assertEquals(HttpServletResponse.SC_OK,exchange2.getResponseStatus());
|
||||
|
||||
//check session de-idled
|
||||
checkSessionDeIdled(storeDir);
|
||||
|
||||
}
|
||||
finally
|
||||
{
|
||||
server1.stop();
|
||||
IO.delete(storeDir);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void checkSessionIdled (File sessionDir)
|
||||
{
|
||||
assertNotNull(sessionDir);
|
||||
assertTrue(sessionDir.exists());
|
||||
String[] files = sessionDir.list();
|
||||
assertNotNull(files);
|
||||
assertEquals(1, files.length);
|
||||
}
|
||||
|
||||
|
||||
public void checkSessionDeIdled (File sessionDir)
|
||||
{
|
||||
assertNotNull(sessionDir);
|
||||
assertTrue(sessionDir.exists());
|
||||
String[] files = sessionDir.list();
|
||||
assertNotNull(files);
|
||||
assertEquals(0, files.length);
|
||||
}
|
||||
|
||||
|
||||
public static class TestServlet extends HttpServlet
|
||||
{
|
||||
public String originalId = null;
|
||||
public String testId = null;
|
||||
public String checkId = null;
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest request, HttpServletResponse httpServletResponse) throws ServletException, IOException
|
||||
{
|
||||
String action = request.getParameter("action");
|
||||
if ("init".equals(action))
|
||||
{
|
||||
HttpSession session = request.getSession(true);
|
||||
session.setAttribute("test", "test");
|
||||
originalId = session.getId();
|
||||
assertTrue(!((HashedSession)session).isIdled());
|
||||
}
|
||||
else if ("test".equals(action))
|
||||
{
|
||||
HttpSession session = request.getSession(false);
|
||||
assertTrue(session != null);
|
||||
assertTrue(originalId.equals(session.getId()));
|
||||
assertEquals("test", session.getAttribute("test"));
|
||||
assertTrue(!((HashedSession)session).isIdled());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue