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 f6e380a43aa..5ce8491a5e1 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
@@ -41,7 +41,10 @@ import org.eclipse.jetty.util.log.Logger;
/* ------------------------------------------------------------ */
-/** An in-memory implementation of SessionManager.
+/**
+ * HashSessionManager
+ *
+ * An in-memory implementation of SessionManager.
*
* 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.
@@ -78,7 +81,7 @@ public class HashSessionManager extends AbstractSessionManager
}
/* ------------------------------------------------------------ */
- /* (non-Javadoc)
+ /**
* @see org.eclipse.jetty.servlet.AbstractSessionManager#doStart()
*/
@Override
@@ -111,7 +114,7 @@ public class HashSessionManager extends AbstractSessionManager
}
/* ------------------------------------------------------------ */
- /* (non-Javadoc)
+ /**
* @see org.eclipse.jetty.servlet.AbstractSessionManager#doStop()
*/
@Override
@@ -253,7 +256,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;
@@ -265,6 +268,7 @@ public class HashSessionManager extends AbstractSessionManager
period=1000;
_scavengePeriodMs=period;
+
if (_timer!=null && (period!=old_period || _task==null))
{
synchronized (this)
@@ -304,25 +308,36 @@ public class HashSessionManager extends AbstractSessionManager
// For each session
long now=System.currentTimeMillis();
+
for (Iterator 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()+idleTime0&&session.getAccessed()+_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);
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/HashedSession.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/HashedSession.java
index 33119f4f977..265680b98a9 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/HashedSession.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/HashedSession.java
@@ -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;
}
/* ------------------------------------------------------------ */
diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/MultiPartFilter.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/MultiPartFilter.java
index d466de34644..5ee0dead19e 100644
--- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/MultiPartFilter.java
+++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/MultiPartFilter.java
@@ -132,7 +132,7 @@ public class MultiPartFilter implements Filter
chain.doFilter(request,response);
return;
}
-
+
InputStream in = new BufferedInputStream(request.getInputStream());
String content_type=srequest.getContentType();
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/MultipartFilterTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/MultipartFilterTest.java
index 38e2c8bbdca..9af2d126af9 100644
--- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/MultipartFilterTest.java
+++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/MultipartFilterTest.java
@@ -42,6 +42,7 @@ import org.eclipse.jetty.servlet.FilterMapping;
import org.eclipse.jetty.testing.HttpTester;
import org.eclipse.jetty.testing.ServletTester;
import org.eclipse.jetty.util.IO;
+import org.eclipse.jetty.util.QuotedStringTokenizer;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -51,7 +52,22 @@ public class MultipartFilterTest
private File _dir;
private ServletTester tester;
-
+
+ public static class BoundaryServlet extends TestServlet
+ {
+ @Override
+ protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
+ {
+ assertNotNull(req.getParameter("fileName"));
+ assertEquals("abc", req.getParameter("fileName"));
+ assertNotNull(req.getParameter("desc"));
+ assertEquals("123", req.getParameter("desc"));
+ assertNotNull(req.getParameter("title"));
+ assertEquals("ttt", req.getParameter("title"));
+ super.doPost(req, resp);
+ }
+ }
+
public static class TestServlet extends DumpServlet
{
@@ -258,6 +274,53 @@ public class MultipartFilterTest
assertEquals(HttpServletResponse.SC_OK,response.getStatus());
assertTrue(response.getContent().indexOf("brown cow")>=0);
}
+
+
+ @Test
+ public void testNoBoundary() throws Exception
+ {
+ // generated and parsed test
+ HttpTester request = new HttpTester();
+ HttpTester response = new HttpTester();
+ tester.addServlet(BoundaryServlet.class,"/testb");
+ request.setMethod("POST");
+ request.setVersion("HTTP/1.0");
+ request.setHeader("Host","tester");
+ request.setURI("/context/testb");
+
+ request.setHeader("Content-Type","multipart/form-data");
+
+ String content = "--\r\n"+
+ "Content-Disposition: form-data; name=\"fileName\"\r\n"+
+ "Content-Type: text/plain; charset=US-ASCII\r\n"+
+ "Content-Transfer-Encoding: 8bit\r\n"+
+ "\r\n"+
+ "abc\r\n"+
+ "--\r\n"+
+ "Content-Disposition: form-data; name=\"desc\"\r\n"+
+ "Content-Type: text/plain; charset=US-ASCII\r\n"+
+ "Content-Transfer-Encoding: 8bit\r\n"+
+ "\r\n"+
+ "123\r\n"+
+ "--\r\n"+
+ "Content-Disposition: form-data; name=\"title\"\r\n"+
+ "Content-Type: text/plain; charset=US-ASCII\r\n"+
+ "Content-Transfer-Encoding: 8bit\r\n"+
+ "\r\n"+
+ "ttt\r\n"+
+ "--\r\n"+
+ "Content-Disposition: form-data; name=\"fileup\"; filename=\"test.upload\"\r\n"+
+ "Content-Type: application/octet-stream\r\n"+
+ "Content-Transfer-Encoding: binary\r\n"+
+ "\r\n"+
+ "000\r\n"+
+ "----\r\n";
+ request.setContent(content);
+
+ response.parse(tester.getResponses(request.generate()));
+ assertTrue(response.getMethod()==null);
+ assertEquals(HttpServletResponse.SC_OK,response.getStatus());
+ }
/*
* see the testParameterMap test
diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/ClasspathPattern.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/ClasspathPattern.java
index 63ec5b4ca76..f6bd679f1c3 100644
--- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/ClasspathPattern.java
+++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/ClasspathPattern.java
@@ -189,16 +189,24 @@ public class ClasspathPattern
if (_entries != null)
{
name = name.replace('/','.');
- name = name.replaceFirst("^[.]+","");
- name = name.replaceAll("\\$.*$","");
-
+
+ int startIndex = 0;
+
+ while(startIndex < name.length() && name.charAt(startIndex) == '.') {
+ startIndex++;
+ }
+
+ int dollar = name.indexOf("$");
+
+ int endIndex = dollar != -1 ? dollar : name.length();
+
for (Entry entry : _entries)
{
if (entry != null)
{
if (entry.partial)
{
- if (name.startsWith(entry.classpath))
+ if (name.regionMatches(startIndex, entry.classpath, 0, entry.classpath.length()))
{
result = entry.result;
break;
@@ -206,7 +214,9 @@ public class ClasspathPattern
}
else
{
- if (name.equals(entry.classpath))
+ int regionLength = endIndex-startIndex;
+ if (regionLength == entry.classpath.length()
+ && name.regionMatches(startIndex, entry.classpath, 0, regionLength))
{
result = entry.result;
break;
diff --git a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/HashTestServer.java b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/HashTestServer.java
index 924a51d6184..25c3ba59ff7 100644
--- a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/HashTestServer.java
+++ b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/HashTestServer.java
@@ -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;
}
diff --git a/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/IdleSessionTest.java b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/IdleSessionTest.java
new file mode 100644
index 00000000000..18dbb430e34
--- /dev/null
+++ b/tests/test-sessions/test-hash-sessions/src/test/java/org/eclipse/jetty/server/session/IdleSessionTest.java
@@ -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());
+ }
+ }
+ }
+}