Merge branch 'master' into jetty-9.4.x-Feature

This commit is contained in:
Greg Wilkins 2016-03-04 16:05:23 +01:00
commit c5f0c80cd2
36 changed files with 1240 additions and 391 deletions

View File

@ -31,6 +31,7 @@ import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.client.api.Response;
import org.eclipse.jetty.client.api.Result;
import org.eclipse.jetty.client.util.BufferingResponseListener;
import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
@ -40,7 +41,6 @@ public abstract class AuthenticationProtocolHandler implements ProtocolHandler
public static final int DEFAULT_MAX_CONTENT_LENGTH = 16*1024;
public static final Logger LOG = Log.getLogger(AuthenticationProtocolHandler.class);
private static final Pattern AUTHENTICATE_PATTERN = Pattern.compile("([^\\s]+)\\s+realm=\"([^\"]+)\"(.*)", Pattern.CASE_INSENSITIVE);
private static final String AUTHENTICATION_ATTRIBUTE = AuthenticationProtocolHandler.class.getName() + ".authentication";
private final HttpClient client;
private final int maxContentLength;
@ -64,6 +64,8 @@ public abstract class AuthenticationProtocolHandler implements ProtocolHandler
protected abstract URI getAuthenticationURI(Request request);
protected abstract String getAuthenticationAttribute();
@Override
public Response.Listener getResponseListener()
{
@ -92,8 +94,9 @@ public abstract class AuthenticationProtocolHandler implements ProtocolHandler
return;
}
String authenticationAttribute = getAuthenticationAttribute();
HttpConversation conversation = request.getConversation();
if (conversation.getAttribute(AUTHENTICATION_ATTRIBUTE) != null)
if (conversation.getAttribute(authenticationAttribute) != null)
{
// We have already tried to authenticate, but we failed again
if (LOG.isDebugEnabled())
@ -146,18 +149,16 @@ public abstract class AuthenticationProtocolHandler implements ProtocolHandler
return;
}
conversation.setAttribute(AUTHENTICATION_ATTRIBUTE, true);
conversation.setAttribute(authenticationAttribute, true);
Request newRequest = client.copyRequest(request, request.getURI());
authnResult.apply(newRequest);
newRequest.onResponseSuccess(new Response.SuccessListener()
{
@Override
public void onSuccess(Response response)
{
client.getAuthenticationStore().addAuthenticationResult(authnResult);
}
}).send(null);
// Copy existing, explicitly set, authorization headers.
copyIfAbsent(request, newRequest, HttpHeader.AUTHORIZATION);
copyIfAbsent(request, newRequest, HttpHeader.PROXY_AUTHORIZATION);
newRequest.onResponseSuccess(r -> client.getAuthenticationStore().addAuthenticationResult(authnResult))
.send(null);
}
catch (Throwable x)
{
@ -167,6 +168,13 @@ public abstract class AuthenticationProtocolHandler implements ProtocolHandler
}
}
private void copyIfAbsent(HttpRequest oldRequest, Request newRequest, HttpHeader header)
{
HttpField field = oldRequest.getHeaders().getField(header);
if (field != null && !newRequest.getHeaders().contains(header))
newRequest.getHeaders().put(field);
}
private void forwardSuccessComplete(HttpRequest request, Response response)
{
HttpConversation conversation = request.getConversation();

View File

@ -153,14 +153,9 @@ public abstract class HttpConnection implements Connection
request.header(HttpHeader.COOKIE.asString(), cookies.toString());
}
// Authorization
URI authenticationURI = proxy != null ? proxy.getURI() : request.getURI();
if (authenticationURI != null)
{
Authentication.Result authnResult = getHttpClient().getAuthenticationStore().findAuthenticationResult(authenticationURI);
if (authnResult != null)
authnResult.apply(request);
}
// Authentication
applyAuthentication(request, proxy != null ? proxy.getURI() : null);
applyAuthentication(request, request.getURI());
}
private StringBuilder convertCookies(List<HttpCookie> cookies, StringBuilder builder)
@ -177,6 +172,16 @@ public abstract class HttpConnection implements Connection
return builder;
}
private void applyAuthentication(Request request, URI uri)
{
if (uri != null)
{
Authentication.Result result = getHttpClient().getAuthenticationStore().findAuthenticationResult(uri);
if (result != null)
result.apply(request);
}
}
protected SendFailure send(HttpChannel channel, HttpExchange exchange)
{
// Forbid idle timeouts for the time window where

View File

@ -34,6 +34,7 @@ import org.eclipse.jetty.http.HttpStatus;
public class ProxyAuthenticationProtocolHandler extends AuthenticationProtocolHandler
{
public static final String NAME = "proxy-authenticate";
private static final String ATTRIBUTE = ProxyAuthenticationProtocolHandler.class.getName() + ".attribute";
public ProxyAuthenticationProtocolHandler(HttpClient client)
{
@ -76,4 +77,10 @@ public class ProxyAuthenticationProtocolHandler extends AuthenticationProtocolHa
ProxyConfiguration.Proxy proxy = destination.getProxy();
return proxy != null ? proxy.getURI() : request.getURI();
}
@Override
protected String getAuthenticationAttribute()
{
return ATTRIBUTE;
}
}

View File

@ -34,6 +34,7 @@ import org.eclipse.jetty.http.HttpStatus;
public class WWWAuthenticationProtocolHandler extends AuthenticationProtocolHandler
{
public static final String NAME = "www-authenticate";
private static final String ATTRIBUTE = WWWAuthenticationProtocolHandler.class.getName() + ".attribute";
public WWWAuthenticationProtocolHandler(HttpClient client)
{
@ -74,4 +75,10 @@ public class WWWAuthenticationProtocolHandler extends AuthenticationProtocolHand
{
return request.getURI();
}
@Override
protected String getAuthenticationAttribute()
{
return ATTRIBUTE;
}
}

View File

@ -81,7 +81,7 @@ public class HttpClientProxyTest extends AbstractHttpClientServerTest
}
@Test
public void testAuthenticatedProxiedRequest() throws Exception
public void testProxyAuthentication() throws Exception
{
final String user = "foo";
final String password = "bar";
@ -160,7 +160,7 @@ public class HttpClientProxyTest extends AbstractHttpClientServerTest
}
@Test
public void testAuthenticatedProxiedRequestWithRedirect() throws Exception
public void testProxyAuthenticationWithRedirect() throws Exception
{
String user = "foo";
String password = "bar";
@ -254,4 +254,148 @@ public class HttpClientProxyTest extends AbstractHttpClientServerTest
Assert.assertEquals(status, response3.getStatus());
Assert.assertEquals(1, requests.get());
}
@Test
public void testProxyAuthenticationWithServerAuthentication() throws Exception
{
String proxyRealm = "proxyRealm";
String serverRealm = "serverRealm";
int status = HttpStatus.NO_CONTENT_204;
start(new AbstractHandler()
{
@Override
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
{
baseRequest.setHandled(true);
String authorization = request.getHeader(HttpHeader.PROXY_AUTHORIZATION.asString());
if (authorization == null)
{
response.setStatus(HttpStatus.PROXY_AUTHENTICATION_REQUIRED_407);
response.setHeader(HttpHeader.PROXY_AUTHENTICATE.asString(), "Basic realm=\"" + proxyRealm + "\"");
}
else
{
authorization = request.getHeader(HttpHeader.AUTHORIZATION.asString());
if (authorization == null)
{
response.setStatus(HttpStatus.UNAUTHORIZED_401);
response.setHeader(HttpHeader.WWW_AUTHENTICATE.asString(), "Basic realm=\"" + serverRealm + "\"");
}
else
{
response.setStatus(status);
}
}
}
});
String proxyHost = "localhost";
int proxyPort = connector.getLocalPort();
String serverHost = "server";
int serverPort = proxyPort + 1;
URI proxyURI = URI.create(scheme + "://" + proxyHost + ":" + proxyPort);
client.getAuthenticationStore().addAuthentication(new BasicAuthentication(proxyURI, proxyRealm, "proxyUser", "proxyPassword"));
URI serverURI = URI.create(scheme + "://" + serverHost + ":" + serverPort);
client.getAuthenticationStore().addAuthentication(new BasicAuthentication(serverURI, serverRealm, "serverUser", "serverPassword"));
client.getProxyConfiguration().getProxies().add(new HttpProxy(proxyHost, proxyPort));
final AtomicInteger requests = new AtomicInteger();
client.getRequestListeners().add(new Request.Listener.Adapter()
{
@Override
public void onSuccess(Request request)
{
requests.incrementAndGet();
}
});
// Make a request, expect 407 + 401 + 204.
ContentResponse response1 = client.newRequest(serverHost, serverPort)
.scheme(scheme)
.timeout(5, TimeUnit.SECONDS)
.send();
Assert.assertEquals(status, response1.getStatus());
Assert.assertEquals(3, requests.get());
// Make again the request, authentication is cached, expect 204.
requests.set(0);
ContentResponse response2 = client.newRequest(serverHost, serverPort)
.scheme(scheme)
.timeout(5, TimeUnit.SECONDS)
.send();
Assert.assertEquals(status, response2.getStatus());
Assert.assertEquals(1, requests.get());
}
@Test
public void testProxyAuthenticationWithExplicitAuthorizationHeader() throws Exception
{
String proxyRealm = "proxyRealm";
String serverRealm = "serverRealm";
int status = HttpStatus.NO_CONTENT_204;
start(new AbstractHandler()
{
@Override
public void handle(String target, org.eclipse.jetty.server.Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
{
baseRequest.setHandled(true);
String authorization = request.getHeader(HttpHeader.PROXY_AUTHORIZATION.asString());
if (authorization == null)
{
response.setStatus(HttpStatus.PROXY_AUTHENTICATION_REQUIRED_407);
response.setHeader(HttpHeader.PROXY_AUTHENTICATE.asString(), "Basic realm=\"" + proxyRealm + "\"");
}
else
{
authorization = request.getHeader(HttpHeader.AUTHORIZATION.asString());
if (authorization == null)
{
response.setStatus(HttpStatus.UNAUTHORIZED_401);
response.setHeader(HttpHeader.WWW_AUTHENTICATE.asString(), "Basic realm=\"" + serverRealm + "\"");
}
else
{
response.setStatus(status);
}
}
}
});
String proxyHost = "localhost";
int proxyPort = connector.getLocalPort();
String serverHost = "server";
int serverPort = proxyPort + 1;
URI proxyURI = URI.create(scheme + "://" + proxyHost + ":" + proxyPort);
client.getAuthenticationStore().addAuthentication(new BasicAuthentication(proxyURI, proxyRealm, "proxyUser", "proxyPassword"));
client.getProxyConfiguration().getProxies().add(new HttpProxy(proxyHost, proxyPort));
final AtomicInteger requests = new AtomicInteger();
client.getRequestListeners().add(new Request.Listener.Adapter()
{
@Override
public void onSuccess(Request request)
{
requests.incrementAndGet();
}
});
// Make a request, expect 407 + 204.
ContentResponse response1 = client.newRequest(serverHost, serverPort)
.scheme(scheme)
.header(HttpHeader.AUTHORIZATION, "Basic foobar")
.timeout(5, TimeUnit.SECONDS)
.send();
Assert.assertEquals(status, response1.getStatus());
Assert.assertEquals(2, requests.get());
// Make again the request, authentication is cached, expect 204.
requests.set(0);
ContentResponse response2 = client.newRequest(serverHost, serverPort)
.scheme(scheme)
.header(HttpHeader.AUTHORIZATION, "Basic foobar")
.timeout(5, TimeUnit.SECONDS)
.send();
Assert.assertEquals(status, response2.getStatus());
Assert.assertEquals(1, requests.get());
}
}

View File

@ -208,7 +208,7 @@ public class InfinispanSessionDataStore extends AbstractSessionDataStore
try
{
Class<?> remoteClass = Thread.currentThread().getContextClassLoader().loadClass("org.infinispan.client.hotrod.RemoteCache");
if (_cache.getClass().isAssignableFrom(remoteClass))
if (remoteClass.isAssignableFrom(_cache.getClass()))
{
return true;
}

View File

@ -44,7 +44,6 @@ public abstract class AbstractSessionStore extends AbstractLifeCycle implements
final static Logger LOG = Log.getLogger("org.eclipse.jetty.server.session");
protected SessionDataStore _sessionDataStore;
protected StalenessStrategy _staleStrategy;
protected SessionManager _manager;
protected SessionContext _context;
protected int _idlePassivationTimeoutSec;
@ -80,6 +79,16 @@ public abstract class AbstractSessionStore extends AbstractLifeCycle implements
public abstract Session doPutIfAbsent (String id, Session session);
/**
* Replace the mapping from id to oldValue with newValue
* @param id
* @param oldValue
* @param newValue
* @return true if replacement was done
*/
public abstract boolean doReplace (String id, Session oldValue, Session newValue);
/**
* Check to see if the session exists in the store
@ -99,6 +108,24 @@ public abstract class AbstractSessionStore extends AbstractLifeCycle implements
/**
* PlaceHolder
*
*
*/
protected class PlaceHolderSession extends Session
{
/**
* @param data
*/
public PlaceHolderSession(SessionData data)
{
super(data);
}
}
/**
*
@ -185,22 +212,7 @@ public abstract class AbstractSessionStore extends AbstractLifeCycle implements
_sessionDataStore = sessionDataStore;
}
/**
* @return the strategy for detecting stale sessions or null if there isn't one
*/
public StalenessStrategy getStaleStrategy()
{
return _staleStrategy;
}
/**
* @param staleStrategy
*/
public void setStaleStrategy(StalenessStrategy staleStrategy)
{
_staleStrategy = staleStrategy;
}
/**
* @see org.eclipse.jetty.server.session.SessionStore#getIdlePassivationTimeoutSec()
@ -238,53 +250,132 @@ public abstract class AbstractSessionStore extends AbstractLifeCycle implements
@Override
public Session get(String id, boolean staleCheck) throws Exception
{
//look locally
Session session = doGet(id);
Session session = null;
Exception ex = null;
//TODO also check that session is only written out if only the access time changes infrequently
//session is either not in session store, or it is stale, or its been passivated, load the data for the session if possible
if (session == null || (staleCheck && isStale(session)) || session.isPassivated() && _sessionDataStore != null)
while (true)
{
SessionData data = _sessionDataStore.load(id);
//session wasn't in session store
session = doGet(id);
if (_sessionDataStore == null)
break; //can't load any session data so just return null or the session object
if (session == null)
{
if (data != null)
if (LOG.isDebugEnabled())
LOG.debug("Session not found locally, attempting to load");
//didn't get a session, try and create one and put in a placeholder for it
PlaceHolderSession phs = new PlaceHolderSession (new SessionData(id, null, null,0,0,0,0));
Lock phsLock = phs.lock();
Session s = doPutIfAbsent(id, phs);
if (s == null)
{
session = newSession(data);
session.setSessionManager(_manager);
Session existing = doPutIfAbsent(id, session);
if (existing != null)
//My placeholder won, go ahead and load the full session data
try
{
//some other thread has got in first and added the session
//so use it
session = existing;
session = loadSession(id);
if (session == null)
{
//session does not exist, remove the placeholder
doDelete(id);
phsLock.close();
break;
}
try (Lock lock = session.lock())
{
//swap it in instead of the placeholder
boolean success = doReplace(id, phs, session);
if (!success)
{
//something has gone wrong, it should have been our placeholder
doDelete(id);
session = null;
LOG.warn("Replacement of placeholder for session {} failed", id);
phsLock.close();
break;
}
//successfully swapped in the session
phsLock.close();
break;
}
}
catch (Exception e)
{
ex = e; //remember a problem happened loading the session
LOG.warn(e);
doDelete(id); //remove the placeholder
phsLock.close();
session = null;
break;
}
}
//else session not in store and not in data store either, so doesn't exist
else
{
//my placeholder didn't win, check the session returned
phsLock.close();
try (Lock lock = s.lock())
{
//is it a placeholder? or is it passivated? In both cases, chuck it away and start again
if (s.isPassivated() || s instanceof PlaceHolderSession)
{
session = null;
continue;
}
session = s;
break;
}
}
}
else
{
//session was already in session store, refresh it if its still stale/passivated
//check the session returned
try (Lock lock = session.lock())
{
if (session.isPassivated() || staleCheck && isStale(session))
{
//is it a placeholder? or is it passivated? In both cases, chuck it away and start again
if (session.isPassivated() || session instanceof PlaceHolderSession)
{
//if we were able to load it, then update our session object
if (data != null)
{
session.setPassivated(false);
session.getSessionData().copy(data);
session.didActivate();
}
else
session = null; //TODO rely on the expiry mechanism to get rid of it?
session = null;
continue;
}
//got the session
break;
}
}
}
if (ex != null)
throw ex;
return session;
}
/**
* Load the info for the session from the session data store
*
* @param id
* @return a Session object filled with data or null if the session doesn't exist
* @throws Exception
*/
private Session loadSession (String id)
throws Exception
{
SessionData data = null;
Session session = null;
if (_sessionDataStore == null)
return null; //can't load it
data =_sessionDataStore.load(id);
if (data == null) //session doesn't exist
return null;
session = newSession(data);
session.setSessionManager(_manager);
return session;
}
@ -300,13 +391,21 @@ public abstract class AbstractSessionStore extends AbstractLifeCycle implements
{
if (id == null || session == null)
throw new IllegalArgumentException ("Put key="+id+" session="+(session==null?"null":session.getId()));
session.setSessionManager(_manager);
//if the session is new, the data has changed, or the cache is considered stale, write it to any backing store
try (Lock lock = session.lock())
{
if ((session.isNew() || session.getSessionData().isDirty() || isStale(session)) && _sessionDataStore != null)
session.setSessionManager(_manager);
if (session.isPassivated())
throw new IllegalStateException ("Session "+id+" is passivated and cannot be saved");
if (!session.isValid())
return;
if ((session.isNew() || session.getSessionData().isDirty()) && _sessionDataStore != null)
{
if (_sessionDataStore.isPassivating())
{
@ -322,11 +421,11 @@ public abstract class AbstractSessionStore extends AbstractLifeCycle implements
}
else
_sessionDataStore.store(id, session.getSessionData());
}
doPutIfAbsent(id,session);
}
doPutIfAbsent(id,session);
}
/**
@ -344,60 +443,28 @@ public abstract class AbstractSessionStore extends AbstractLifeCycle implements
/**
* Remove a session object from this store and from any backing store.
*
* If session has been passivated, may need to reload it before it can
* be properly deleted
*
* @see org.eclipse.jetty.server.session.SessionStore#delete(java.lang.String)
*/
@Override
public Session delete(String id) throws Exception
{
//Ensure that the session object is not passivated so that its attributes
//are valid
Session session = doGet(id);
//TODO if (session == null) do we want to load it to delete it?
if (session != null)
{
try (Lock lock = session.lock())
{
//TODO don't check stale on deletion?
if (session.isPassivated() && _sessionDataStore != null)
{
session.setPassivated(false);
SessionData data = _sessionDataStore.load(id);
if (data != null)
{
session.getSessionData().copy(data);
session.didActivate();
}
}
}
}
//Always delete it from the data store
{
//get the session, if its not in memory, this will load it
Session session = get(id, false);
//Always delete it from the backing data store
if (_sessionDataStore != null)
{
boolean dsdel = _sessionDataStore.delete(id);
if (LOG.isDebugEnabled()) LOG.debug("Session {} deleted in db {}",id, dsdel);
}
//delete it from the session object store
return doDelete(id);
}
/**
* @param session
* @return true or false according to the StaleStrategy
*/
public boolean isStale (Session session)
{
if (_staleStrategy != null)
return _staleStrategy.isStale(session);
return false;
}
@ -443,8 +510,8 @@ public abstract class AbstractSessionStore extends AbstractLifeCycle implements
/**
* If the SessionDataStore supports passivation, passivate any
* sessions that have not be accessed for longer than x sec
* If the SessionDataStore supports passivation,
* write the session to the backing data store.
*
* @param id identity of session to passivate
*/
@ -453,12 +520,8 @@ public abstract class AbstractSessionStore extends AbstractLifeCycle implements
if (!isStarted())
return;
if (_sessionDataStore == null)
return; //no data store to passivate
if (!_sessionDataStore.isPassivating())
return; //doesn't support passivation
if (_sessionDataStore == null || !_sessionDataStore.isPassivating())
return; //no data store to passivate or it doesn't passivate
//get the session locally
Session s = doGet(id);
@ -470,22 +533,34 @@ public abstract class AbstractSessionStore extends AbstractLifeCycle implements
}
//lock the session during passivation
try (Lock lock = s.lock())
{
//check the session is still idle first
if (s.isValid() && s.isIdleLongerThan(_idlePassivationTimeoutSec))
//check the session is still idle and that it doesn't have requests using it
if (s.isValid() && s.isIdleLongerThan(_idlePassivationTimeoutSec) && s.isActive() && (s.getRequests() <= 0))
{
s.willPassivate();
_sessionDataStore.store(id, s.getSessionData());
s.getSessionData().clearAllAttributes();
s.getSessionData().setDirty(false);
//TODO - do we need to check that the session exists in the session data store
//before we passivate it? If it doesn't exist, we can assume another node
//invalidated it. If the session was new, it shouldn't have been idle passivated.
try
{
if (LOG.isDebugEnabled())
LOG.debug("Passivating idle session {}", id);
s.willPassivate();
_sessionDataStore.store(id, s.getSessionData());
s.getSessionData().setDirty(false);
s.setPassivated();
doDelete(id); //Take the session object of this session store
}
catch (Exception e)
{
LOG.warn("Passivation of idle session {} failed", id, e);
s.setPassivated(); //set it as passivated so it can't be used
doDelete(id); //detach it
}
}
}
catch (Exception e)
{
LOG.warn("Passivation of idle session {} failed", id, e);
// TODO should do session.invalidate(); ???
}
}

View File

@ -27,13 +27,20 @@ package org.eclipse.jetty.server.session;
*/
public class FileSessionManager extends SessionManager
{
protected FileSessionDataStore _sessionDataStore = new FileSessionDataStore();
protected FileSessionDataStore _sessionDataStore;
/**
*
*/
public FileSessionManager ()
{
_sessionStore = new MemorySessionStore();
_sessionDataStore = new FileSessionDataStore();
}
@Override
public void doStart() throws Exception
{
_sessionStore = new MemorySessionStore();
((AbstractSessionStore)_sessionStore).setSessionDataStore(_sessionDataStore);
super.doStart();

View File

@ -81,6 +81,8 @@ public class IdleInspector implements SessionInspector
public void preInspection()
{
_idleCandidates = new HashSet<String>();
if (LOG.isDebugEnabled())
LOG.debug("IdleInspector preinspection");
}
@ -91,6 +93,9 @@ public class IdleInspector implements SessionInspector
@Override
public void postInspection()
{
if (LOG.isDebugEnabled())
LOG.debug("IdleInspector postinspection");
for (String id:_idleCandidates)
{
try

View File

@ -717,7 +717,6 @@ public class JDBCSessionDataStore extends AbstractSessionDataStore
//ensure this runs with context classloader set
_context.run(r);
if (exception.get() != null)
throw exception.get();

View File

@ -124,7 +124,7 @@ public class MemorySessionStore extends AbstractSessionStore
public Session doPutIfAbsent(String id, Session session)
{
Session s = _sessions.putIfAbsent(id, session);
if (s == null)
if (s == null && !(session instanceof PlaceHolderSession))
_stats.increment();
return s;
}
@ -145,31 +145,11 @@ public class MemorySessionStore extends AbstractSessionStore
public Session doDelete(String id)
{
Session s = _sessions.remove(id);
if (s != null)
if (s != null && !(s instanceof PlaceHolderSession))
_stats.decrement();
return s;
}
/*
@Override
public Set<String> doGetExpiredCandidates()
{
Set<String> candidates = new HashSet<String>();
long now = System.currentTimeMillis();
for (Session s:_sessions.values())
{
if (s.isExpiredAt(now))
{
candidates.add(s.getId());
}
}
return candidates;
}
*/
@ -253,4 +233,17 @@ public class MemorySessionStore extends AbstractSessionStore
}
/**
* @see org.eclipse.jetty.server.session.AbstractSessionStore#doReplace(java.lang.String, org.eclipse.jetty.server.session.Session, org.eclipse.jetty.server.session.Session)
*/
@Override
public boolean doReplace(String id, Session oldValue, Session newValue)
{
boolean result = _sessions.replace(id, oldValue, newValue);
if (result && (oldValue instanceof PlaceHolderSession))
_stats.increment();
return result;
}
}

View File

@ -51,11 +51,27 @@ public class Session implements SessionManager.SessionIf
private final static Logger LOG = Log.getLogger("org.eclipse.jetty.server.session");
/**
*
*/
public final static String SESSION_CREATED_SECURE="org.eclipse.jetty.security.sessionCreatedSecure";
/**
* State
*
* Validity states of a session
*/
public enum State {VALID, INVALID, INVALIDATING};
/**
* PassivationState
*
* States of a session - either active in memory or passivated to persistent store
*/
public enum PassivationState {PASSIVATED, ACTIVE};
protected SessionData _sessionData;
protected SessionManager _manager;
@ -66,24 +82,52 @@ public class Session implements SessionManager.SessionIf
private State _state = State.VALID; //state of the session:valid,invalid or being invalidated
private Locker _lock = new Locker();
private PassivationState _passivationState = PassivationState.ACTIVE;
private boolean _isPassivated;
/**
* Create a new session
*
* @param request
* @param data
*/
public Session (HttpServletRequest request, SessionData data)
{
_sessionData = data;
_newSession = true;
_requests = 1;
_requests = 1; //access will not be called on this new session, but we are obviously in a request
}
/**
* Re-create an existing session
* @param data
*/
public Session (SessionData data)
{
_sessionData = data;
_requests = 1;
}
/**
* Should call this method with a lock held if you want to
* make decision on what to do with the session
*
* @return
*/
public long getRequests()
{
try (Lock lock = _lock.lockIfNotHeld())
{
return _requests;
}
}
public void setSessionManager (SessionManager manager)
{
_manager = manager;
@ -98,7 +142,7 @@ public class Session implements SessionManager.SessionIf
/* ------------------------------------------------------------- */
protected void cookieSet()
{
try (Lock lock = lock())
try (Lock lock = _lock.lockIfNotHeld())
{
_sessionData.setCookieSet(_sessionData.getAccessed());
}
@ -106,7 +150,7 @@ public class Session implements SessionManager.SessionIf
/* ------------------------------------------------------------ */
protected boolean access(long time)
{
try (Lock lock=lock())
try (Lock lock = _lock.lockIfNotHeld())
{
if (!isValid())
return false;
@ -129,7 +173,7 @@ public class Session implements SessionManager.SessionIf
/* ------------------------------------------------------------ */
protected void complete()
{
try (Lock lock = lock())
try (Lock lock = _lock.lockIfNotHeld())
{
_requests--;
}
@ -363,7 +407,7 @@ public class Session implements SessionManager.SessionIf
@Override
public void setMaxInactiveInterval(int secs)
{
try (Lock lock = lock())
try (Lock lock = _lock.lockIfNotHeld())
{
_sessionData.setMaxInactiveMs((long)secs*1000L);
_sessionData.setExpiry(_sessionData.getMaxInactiveMs() <= 0 ? 0 : (System.currentTimeMillis() + _sessionData.getMaxInactiveMs()*1000L));
@ -407,11 +451,13 @@ public class Session implements SessionManager.SessionIf
*/
protected void checkValidForWrite() throws IllegalStateException
{
if (!_lock.isLocked())
throw new IllegalStateException();
checkLocked();
if (_state != State.VALID)
throw new IllegalStateException();
if (_passivationState == PassivationState.PASSIVATED)
throw new IllegalStateException("Passivated");
}
@ -422,14 +468,26 @@ public class Session implements SessionManager.SessionIf
*/
protected void checkValidForRead () throws IllegalStateException
{
if (!_lock.isLocked())
throw new IllegalStateException();
checkLocked();
if (_state == State.INVALID)
throw new IllegalStateException();
throw new IllegalStateException("Invalid");
if (_passivationState == PassivationState.PASSIVATED)
throw new IllegalStateException("Passivated");
}
/* ------------------------------------------------------------- */
/**
* @throws IllegalStateException
*/
protected void checkLocked ()
throws IllegalStateException
{
if (!_lock.isLocked())
throw new IllegalStateException("Session not locked");
}
/**
* @see javax.servlet.http.HttpSession#getAttribute(java.lang.String)
@ -750,7 +808,7 @@ public class Session implements SessionManager.SessionIf
/* ------------------------------------------------------------- */
public void setIdChanged(boolean changed)
{
try (Lock lock = lock())
try (Lock lock = _lock.lockIfNotHeld())
{
_idChanged=changed;
}
@ -784,25 +842,46 @@ public class Session implements SessionManager.SessionIf
return _sessionData;
}
/* ------------------------------------------------------------- */
/**
*
*/
public void setPassivated ()
{
checkLocked();
_passivationState = PassivationState.PASSIVATED;
}
/**
*
*/
public void setActive ()
{
checkLocked();
_passivationState = PassivationState.ACTIVE;
}
/**
* @return
*/
public boolean isPassivated()
public boolean isActive ()
{
return _isPassivated;
checkLocked();
return _passivationState == PassivationState.ACTIVE;
}
/* ------------------------------------------------------------- */
/**
* @param isPassivated
* @return
*/
public void setPassivated(boolean isPassivated)
public boolean isPassivated ()
{
_isPassivated = isPassivated;
checkLocked();
return _passivationState == PassivationState.PASSIVATED;
}
}

View File

@ -53,6 +53,7 @@ import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.statistic.CounterStatistic;
import org.eclipse.jetty.util.statistic.SampleStatistic;
import org.eclipse.jetty.util.thread.Locker.Lock;
@ -221,11 +222,11 @@ public class SessionManager extends ContainerLifeCycle implements org.eclipse.je
public void complete(HttpSession session)
{
Session s = ((SessionIf)session).getSession();
s.complete();
try
{
if (s.isValid())
_sessionStore.put(s.getId(), s);
s.complete();
_sessionStore.put(s.getId(), s);
}
catch (Exception e)
{
@ -574,6 +575,7 @@ public class SessionManager extends ContainerLifeCycle implements org.eclipse.je
@Override
public HttpSession newHttpSession(HttpServletRequest request)
{
long created=System.currentTimeMillis();
String id =_sessionIdManager.newSessionId(request,created);
Session session = _sessionStore.newSession(request, id, created, (_dftMaxIdleSecs>0?_dftMaxIdleSecs*1000L:-1));
@ -583,7 +585,6 @@ public class SessionManager extends ContainerLifeCycle implements org.eclipse.je
session.getSessionData().setExpiry(_dftMaxIdleSecs <= 0 ? 0 : (created + _dftMaxIdleSecs*1000L));
if (request.isSecure())
session.setAttribute(Session.SESSION_CREATED_SECURE, Boolean.TRUE);
try
{
_sessionStore.put(id, session);

View File

@ -18,8 +18,6 @@
package org.eclipse.jetty.server.handler;
import static org.hamcrest.Matchers.is;
import java.io.File;
import java.io.FileWriter;
import java.io.InputStream;
@ -38,7 +36,9 @@ import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
@Ignore("Unfixed range bug")
import static org.hamcrest.Matchers.is;
@Ignore("Unfixed range bug - Issue #107")
public class ResourceHandlerRangeTest
{
private static Server server;

View File

@ -123,6 +123,16 @@ public class SessionCookieTest
return null;
}
/**
* @see org.eclipse.jetty.server.session.AbstractSessionStore#doReplace(java.lang.String, org.eclipse.jetty.server.session.Session, org.eclipse.jetty.server.session.Session)
*/
@Override
public boolean doReplace(String id, Session oldValue, Session newValue)
{
// TODO Auto-generated method stub
return false;
}
}

View File

@ -1113,6 +1113,8 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor
code=Integer.valueOf(error);
String location = node.getString("location", false, true);
if (!location.startsWith("/"))
throw new IllegalStateException("Missing leading '/' for location: " + location);
ErrorPageErrorHandler handler = (ErrorPageErrorHandler)context.getErrorHandler();
String originName = "error."+error;
switch (context.getMetaData().getOrigin(originName))

View File

@ -18,6 +18,11 @@
package org.eclipse.jetty.server.session;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertFalse;
import java.io.File;
import org.eclipse.jetty.server.SessionIdManager;
@ -50,6 +55,70 @@ public class FileTestServer extends AbstractTestServer
}
public static void assertStoreDirEmpty (boolean isEmpty)
{
assertNotNull(_tmpDir);
assertTrue(_tmpDir.exists());
String[] files = _tmpDir.list();
if (isEmpty)
{
if (files != null)
assertEquals(0, files.length);
}
else
{
assertNotNull(files);
assertFalse(files.length==0);
}
}
public static void assertFileExists (String sessionId, boolean exists)
{
assertNotNull(_tmpDir);
assertTrue(_tmpDir.exists());
String[] files = _tmpDir.list();
assertNotNull(files);
assertFalse(files.length == 0);
boolean found = false;
for (String name:files)
{
if (name.contains(sessionId))
{
found = true;
break;
}
}
if (exists)
assertTrue(found);
else
assertFalse(found);
}
public static void deleteFile (String sessionId)
{
assertNotNull(_tmpDir);
assertTrue(_tmpDir.exists());
String[] files = _tmpDir.list();
assertNotNull(files);
assertFalse(files.length == 0);
String filename = null;
for (String name:files)
{
if (name.contains(sessionId))
{
filename = name;
break;
}
}
if (filename != null)
{
File f = new File (_tmpDir, filename);
assertTrue(f.delete());
}
}
public FileTestServer(int port)
{

View File

@ -0,0 +1,107 @@
//
// ========================================================================
// Copyright (c) 1995-2016 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 org.eclipse.jetty.server.SessionManager;
import org.junit.After;
import org.junit.Before;
/**
* IdleSessionTest
*
*
*/
public class IdleSessionTest extends AbstractIdleSessionTest
{
@Before
public void before() throws Exception
{
FileTestServer.setup();
}
@After
public void after()
{
FileTestServer.teardown();
}
/**
* @see org.eclipse.jetty.server.session.AbstractIdleSessionTest#createServer(int, int, int, int)
*/
@Override
public AbstractTestServer createServer(final int port, final int max, final int scavenge, final int idleSec)
{
FileTestServer server = new FileTestServer(port,max,scavenge)
{
/**
* @see org.eclipse.jetty.server.session.FileTestServer#newSessionManager()
*/
@Override
public SessionManager newSessionManager()
{
FileSessionManager manager = (FileSessionManager)super.newSessionManager();
manager.getSessionStore().setIdlePassivationTimeoutSec(idleSec);
return manager;
}
};
return server;
}
/**
* @see org.eclipse.jetty.server.session.AbstractIdleSessionTest#checkSessionIdled(java.lang.String)
*/
@Override
public void checkSessionIdled(String sessionId)
{
FileTestServer.assertStoreDirEmpty(false);
FileTestServer.assertFileExists(sessionId, true);
}
/**
* @see org.eclipse.jetty.server.session.AbstractIdleSessionTest#checkSessionDeIdled(java.lang.String)
*/
@Override
public void checkSessionDeIdled(String sessionId)
{
//Can't check absence of file to indicate session is de-idled
//because the FileSessionStore writes out the session to a file if anything changes.
//The test changes an attribute so the file will probably exist.
}
/**
* @see org.eclipse.jetty.server.session.AbstractIdleSessionTest#deleteSessionData(java.lang.String)
*/
@Override
public void deleteSessionData(String sessionId)
{
FileTestServer.deleteFile(sessionId);
}
}

View File

@ -37,7 +37,6 @@ import com.google.gcloud.datastore.DatastoreFactory;
public class GCloudTestServer extends AbstractTestServer
{
static int __workers=0;
public static int STALE_INTERVAL_SEC = 1;
@ -82,9 +81,6 @@ public class GCloudTestServer extends AbstractTestServer
GCloudSessionManager sessionManager = new GCloudSessionManager();
sessionManager.setSessionIdManager((GCloudSessionIdManager)_sessionIdManager);
sessionManager.getSessionDataStore().setGCloudConfiguration(((GCloudSessionIdManager)_sessionIdManager).getConfig());
StalePeriodStrategy staleStrategy = new StalePeriodStrategy();
staleStrategy.setStaleSec(STALE_INTERVAL_SEC);
((AbstractSessionStore)sessionManager.getSessionStore()).setStaleStrategy(staleStrategy);
return sessionManager;
}

View File

@ -19,10 +19,12 @@
package org.eclipse.jetty.gcloud.session;
import org.eclipse.jetty.server.SessionManager;
import org.eclipse.jetty.server.session.AbstractInvalidationSessionTest;
import org.eclipse.jetty.server.session.AbstractTestServer;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Ignore;
/**
* InvalidationSessionTest
@ -32,6 +34,7 @@ import org.junit.BeforeClass;
public class InvalidationSessionTest extends AbstractInvalidationSessionTest
{
static GCloudSessionTestSupport _testSupport;
public static final int IDLE_PASSIVATE_SEC = 3;
@BeforeClass
public static void setup () throws Exception
@ -50,9 +53,23 @@ public class InvalidationSessionTest extends AbstractInvalidationSessionTest
* @see org.eclipse.jetty.server.session.AbstractInvalidationSessionTest#createServer(int)
*/
@Override
public AbstractTestServer createServer(int port)
public AbstractTestServer createServer(int port, int maxInactive, int inspectInterval)
{
return new GCloudTestServer(port, _testSupport.getConfiguration());
GCloudTestServer server = new GCloudTestServer(port, maxInactive, inspectInterval, _testSupport.getConfiguration())
{
/**
* @see org.eclipse.jetty.gcloud.session.GCloudTestServer#newSessionManager()
*/
@Override
public SessionManager newSessionManager()
{
GCloudSessionManager manager = (GCloudSessionManager)super.newSessionManager();
manager.getSessionStore().setIdlePassivationTimeoutSec(IDLE_PASSIVATE_SEC);
return manager;
}
};
return server;
}
/**
@ -66,7 +83,7 @@ public class InvalidationSessionTest extends AbstractInvalidationSessionTest
//has expired on node2 for it to reload the session and discover it has been deleted.
try
{
Thread.currentThread().sleep((2*GCloudTestServer.STALE_INTERVAL_SEC)*1000);
Thread.currentThread().sleep((2*IDLE_PASSIVATE_SEC)*1000);
}
catch (Exception e)
{
@ -75,4 +92,17 @@ public class InvalidationSessionTest extends AbstractInvalidationSessionTest
}
/**
* @see org.eclipse.jetty.server.session.AbstractInvalidationSessionTest#testInvalidation()
*/
@Ignore
@Override
public void testInvalidation() throws Exception
{
// Ignore
//super.testInvalidation();
}
}

View File

@ -26,6 +26,8 @@ import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.Assert;
/**
* SessionExpiryTest
@ -76,21 +78,21 @@ public class SessionExpiryTest extends AbstractSessionExpiryTest
public void testSessionExpiry() throws Exception
{
super.testSessionExpiry();
_testSupport.assertSessions(0);
try{_testSupport.assertSessions(0);}catch(Exception e){ Assert.fail(e.getMessage());}
}
@Override
public void verifySessionCreated(TestHttpSessionListener listener, String sessionId)
{
super.verifySessionCreated(listener, sessionId);
try{ _testSupport.listSessions(); _testSupport.assertSessions(1);}catch(Exception e) {e.printStackTrace();}
try {_testSupport.assertSessions(1);}catch(Exception e){ Assert.fail(e.getMessage());}
}
@Override
public void verifySessionDestroyed(TestHttpSessionListener listener, String sessionId)
{
super.verifySessionDestroyed(listener, sessionId);
try{ _testSupport.listSessions(); _testSupport.assertSessions(0);}catch(Exception e) {e.printStackTrace();}
try{_testSupport.assertSessions(0);}catch(Exception e){ Assert.fail(e.getMessage());}
}

View File

@ -22,6 +22,7 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.io.File;
import java.io.IOException;
@ -40,6 +41,7 @@ import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.StdErrLog;
import org.eclipse.jetty.util.thread.Locker.Lock;
import org.junit.Test;
@ -48,7 +50,7 @@ import org.junit.Test;
*
* Checks that a session can be idled and de-idled on the next request if it hasn't expired.
*
* TODO support session idling in FileSessionDataStore?
*
*
*/
public class IdleSessionTest
@ -69,9 +71,9 @@ public class IdleSessionTest
@Override
public SessionManager newSessionManager()
{
HashSessionManager manager = (HashSessionManager)super.newSessionManager();
//manager.getSessionDataStore().setStoreDir(_storeDir);
//manager.setIdleSavePeriod(_idlePeriod);
FileSessionManager manager = new FileSessionManager();
manager.getSessionStore().setIdlePassivationTimeoutSec(_idlePeriod);
manager.getSessionDataStore().setStoreDir(_storeDir);
return manager;
}
@ -98,6 +100,7 @@ public class IdleSessionTest
}
}
@Test
public void testSessionIdle() throws Exception
{
String contextPath = "";
@ -134,9 +137,9 @@ public class IdleSessionTest
//and wait until the session should be idled out
pause(idlePeriod * 2);
//check that the file exists
checkSessionIdled(storeDir, getSessionId(sessionCookie));
checkSessionIdled(storeDir, HashTestServer.extractSessionId(sessionCookie));
//make another request to de-idle the session
Request request = client.newRequest(url + "?action=test");
@ -151,11 +154,11 @@ public class IdleSessionTest
pause(idlePeriod * 2);
//check that it is
checkSessionIdled(storeDir, getSessionId(sessionCookie));
checkSessionIdled(storeDir, HashTestServer.extractSessionId(sessionCookie));
//delete the file
File idleFile = getIdleFile(storeDir, getSessionId(sessionCookie));
File idleFile = getIdleFile(storeDir, HashTestServer.extractSessionId(sessionCookie));
assertTrue(idleFile.exists());
assertTrue(idleFile.delete());
@ -173,6 +176,10 @@ public class IdleSessionTest
}
/**
* @param sessionDir
* @param sessionId
*/
public void checkSessionIdled (File sessionDir, String sessionId)
{
assertNotNull(sessionDir);
@ -180,10 +187,13 @@ public class IdleSessionTest
String[] files = sessionDir.list();
assertNotNull(files);
assertEquals(1, files.length);
assertEquals(sessionId, files[0]);
assertTrue(files[0].contains(sessionId));
}
/**
* @param sessionDir
*/
public void checkSessionDeIdled (File sessionDir)
{
assertNotNull(sessionDir);
@ -193,6 +203,11 @@ public class IdleSessionTest
assertEquals(0, files.length);
}
/**
* @param sessionDir
* @param sessionId
* @return
*/
public File getIdleFile (File sessionDir, String sessionId)
{
assertNotNull(sessionDir);
@ -202,13 +217,6 @@ public class IdleSessionTest
return new File(sessionDir, files[0]);
}
public String getSessionId (String sessionCookie)
{
assertNotNull(sessionCookie);
String sessionId = sessionCookie.substring(11);
sessionId = sessionId.substring(0, sessionId.indexOf(';'));
return sessionId;
}
public static class TestServlet extends HttpServlet
{
@ -223,7 +231,11 @@ public class IdleSessionTest
HttpSession session = request.getSession(true);
session.setAttribute("test", "test");
originalId = session.getId();
// assertTrue(!((HashedSession)session).isIdled());
Session s = (Session)session;
try (Lock lock = s.lock())
{
assertTrue(!s.isPassivated());
}
}
else if ("test".equals(action))
{
@ -231,7 +243,6 @@ public class IdleSessionTest
assertTrue(session != null);
assertTrue(originalId.equals(session.getId()));
assertEquals("test", session.getAttribute("test"));
// assertTrue(!((HashedSession)session).isIdled());
}
else if ("testfail".equals(action))
{

View File

@ -1,38 +0,0 @@
//
// ========================================================================
// Copyright (c) 1995-2016 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 org.junit.Test;
/**
* OrphanedSessionTest
*/
public class OrphanedSessionTest extends AbstractOrphanedSessionTest
{
public AbstractTestServer createServer(int port, int max, int scavenge)
{
return new HashTestServer(port,max,scavenge);
}
@Test
public void testOrphanedSession() throws Exception
{
super.testOrphanedSession();
}
}

View File

@ -65,9 +65,6 @@ public class InfinispanTestSessionServer extends AbstractTestServer
InfinispanSessionManager sessionManager = new InfinispanSessionManager();
sessionManager.setSessionIdManager((InfinispanSessionIdManager)_sessionIdManager);
sessionManager.getSessionDataStore().setCache(((InfinispanSessionIdManager)_sessionIdManager).getCache());
StalePeriodStrategy staleStrategy = new StalePeriodStrategy();
staleStrategy.setStaleSec(1);
((AbstractSessionStore)sessionManager.getSessionStore()).setStaleStrategy(staleStrategy);
return sessionManager;
}

View File

@ -1,91 +0,0 @@
//
// ========================================================================
// Copyright (c) 1995-2016 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 org.junit.AfterClass;
import org.junit.BeforeClass;
/**
* InvalidationSessionTest
*
*
*/
public class InvalidationSessionTest extends AbstractInvalidationSessionTest
{
public static InfinispanTestSupport __testSupport;
public static long __staleSec = 3L;
@BeforeClass
public static void setup () throws Exception
{
__testSupport = new InfinispanTestSupport();
__testSupport.setup();
}
@AfterClass
public static void teardown () throws Exception
{
__testSupport.teardown();
}
/**
* @see org.eclipse.jetty.server.session.AbstractInvalidationSessionTest#createServer(int)
*/
@Override
public AbstractTestServer createServer(int port)
{
return new InfinispanTestSessionServer(port, __testSupport.getCache());
}
@Override
public void testInvalidation() throws Exception
{
super.testInvalidation();
}
/**
* @see org.eclipse.jetty.server.session.AbstractInvalidationSessionTest#pause()
*/
@Override
public void pause()
{
//This test moves a session from node 1 to node 2, then invalidates the session back on node1. This
//should never happen with a decent load balancer.
//The infinispan session manager on node 2 will hold the session in local memory for a specific (configurable)
//amount of time. We've set the stale session time to 3 sec, so we need to pause for at least this long before making
//another request to node2
//that the node will re-load the session from the database and discover that it has gone.
try
{
Thread.sleep(2 * __staleSec * 1000);
}
catch (InterruptedException e)
{
}
}
}

View File

@ -19,11 +19,14 @@
package org.eclipse.jetty.server.session.remote;
import org.eclipse.jetty.server.SessionManager;
import org.eclipse.jetty.server.session.AbstractInvalidationSessionTest;
import org.eclipse.jetty.server.session.AbstractTestServer;
import org.eclipse.jetty.server.session.InfinispanTestSessionServer;
import org.eclipse.jetty.session.infinispan.InfinispanSessionManager;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Ignore;
/**
* InvalidationSessionTest
@ -34,7 +37,7 @@ public class RemoteInvalidationSessionTest extends AbstractInvalidationSessionTe
{
public static RemoteInfinispanTestSupport __testSupport;
public static long __staleSec = 3L;
public static final int IDLE_PASSIVATE_SEC = 3;
@ -55,18 +58,34 @@ public class RemoteInvalidationSessionTest extends AbstractInvalidationSessionTe
* @see org.eclipse.jetty.server.session.AbstractInvalidationSessionTest#createServer(int)
*/
@Override
public AbstractTestServer createServer(int port)
public AbstractTestServer createServer(int port, int maxInterval, int inspectInterval)
{
return new InfinispanTestSessionServer(port, __testSupport.getCache());
InfinispanTestSessionServer server = new InfinispanTestSessionServer(port, maxInterval, inspectInterval, __testSupport.getCache())
{
/**
* @see org.eclipse.jetty.server.session.InfinispanTestSessionServer#newSessionManager()
*/
@Override
public SessionManager newSessionManager()
{
InfinispanSessionManager mgr = (InfinispanSessionManager)super.newSessionManager();
mgr.getSessionStore().setIdlePassivationTimeoutSec(IDLE_PASSIVATE_SEC);
return mgr;
}
};
return server;
}
@Ignore
@Override
public void testInvalidation() throws Exception
{
super.testInvalidation();
//Ignore
//super.testInvalidation();
}
/**
@ -83,7 +102,7 @@ public class RemoteInvalidationSessionTest extends AbstractInvalidationSessionTe
//that the node will re-load the session from the database and discover that it has gone.
try
{
Thread.sleep(2 * __staleSec * 1000);
Thread.sleep(2 * IDLE_PASSIVATE_SEC * 1000);
}
catch (InterruptedException e)
{

View File

@ -18,6 +18,7 @@
package org.eclipse.jetty.server.session;
import org.eclipse.jetty.server.SessionManager;
import org.junit.After;
import org.junit.Test;
@ -26,9 +27,26 @@ import org.junit.Test;
*/
public class InvalidationSessionTest extends AbstractInvalidationSessionTest
{
public AbstractTestServer createServer(int port)
public static final int IDLE_PASSIVATE_SEC = 3;
public AbstractTestServer createServer(int port, int maxInactive, int inspectInterval)
{
return new JdbcTestServer(port);
JdbcTestServer server = new JdbcTestServer(port, maxInactive, inspectInterval)
{
/**
* @see org.eclipse.jetty.server.session.JdbcTestServer#newSessionManager()
*/
@Override
public SessionManager newSessionManager()
{
JDBCSessionManager manager = (JDBCSessionManager)super.newSessionManager();
manager.getSessionStore().setIdlePassivationTimeoutSec(IDLE_PASSIVATE_SEC);
return manager;
}
};
return server;
}
public void pause()
@ -40,7 +58,7 @@ public class InvalidationSessionTest extends AbstractInvalidationSessionTest
//that the node will re-load the session from the database and discover that it has gone.
try
{
Thread.sleep(2 * JdbcTestServer.STALE_INTERVAL * 1000);
Thread.sleep(2 * IDLE_PASSIVATE_SEC * 1000);
}
catch (InterruptedException e)
{

View File

@ -137,7 +137,7 @@ public class JdbcTestServer extends AbstractTestServer
JDBCSessionManager manager = new JDBCSessionManager();
manager.setSessionIdManager((JDBCSessionIdManager)_sessionIdManager);
JDBCSessionDataStore ds = manager.getSessionDataStore();
ds.setGracePeriodSec(_scavengePeriod);
ds.setGracePeriodSec(_inspectionPeriod);
manager.getDatabaseAdaptor().setDriverInfo(DRIVER_CLASS, DEFAULT_CONNECTION_URL);
JDBCSessionDataStore.SessionTableSchema sessionTableSchema = new JDBCSessionDataStore.SessionTableSchema();
sessionTableSchema.setTableName(TABLE);
@ -153,9 +153,6 @@ public class JdbcTestServer extends AbstractTestServer
sessionTableSchema.setMapColumn(MAP_COL);
sessionTableSchema.setMaxIntervalColumn(MAX_IDLE_COL);
ds.setSessionTableSchema(sessionTableSchema);
StalePeriodStrategy staleStrategy = new StalePeriodStrategy();
staleStrategy.setStaleSec(STALE_INTERVAL);
((AbstractSessionStore)manager.getSessionStore()).setStaleStrategy(staleStrategy);
return manager;
}

View File

@ -21,6 +21,7 @@ package org.eclipse.jetty.server.session;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertFalse;
import java.io.File;
import java.io.FileWriter;
@ -125,8 +126,10 @@ public class ReloadedSessionMissingClassTest
response = request.send();
assertEquals(HttpServletResponse.SC_OK,response.getStatus());
String afterStopSessionId = (String)webApp.getServletContext().getAttribute("foo.session");
Boolean fooPresent = (Boolean)webApp.getServletContext().getAttribute("foo.present");
assertFalse(fooPresent);
assertNotNull(afterStopSessionId);
assertFalse(fooPresent);
assertTrue(!afterStopSessionId.equals(sessionId));
}

View File

@ -67,9 +67,9 @@ public class SaveIntervalTest
holder.setServlet(servlet);
ctxA.addServlet(holder, "/test");
StalePeriodStrategy strategy = new StalePeriodStrategy();
strategy.setStaleSec(SAVE);
((AbstractSessionStore)((JDBCSessionManager)ctxA.getSessionHandler().getSessionManager()).getSessionStore()).setStaleStrategy(strategy);
//TODO set up the intermittent save
server.start();
int port=server.getPort();
try

View File

@ -0,0 +1,111 @@
//
// ========================================================================
// Copyright (c) 1995-2016 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.nosql.mongodb;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import org.eclipse.jetty.server.SessionManager;
import org.eclipse.jetty.server.session.AbstractIdleSessionTest;
import org.eclipse.jetty.server.session.AbstractTestServer;
import org.eclipse.jetty.server.session.Session;
import org.eclipse.jetty.util.thread.Locker.Lock;
/**
* IdleSessionTest
*
*
*/
public class IdleSessionTest extends AbstractIdleSessionTest
{
/**
* @see org.eclipse.jetty.server.session.AbstractIdleSessionTest#createServer(int, int, int, int)
*/
@Override
public AbstractTestServer createServer(final int port, final int max, final int scavenge, final int idleSec)
{
MongoTestServer server = new MongoTestServer(port,max,scavenge)
{
/**
* @see org.eclipse.jetty.nosql.mongodb.MongoTestServer#newSessionManager()
*/
@Override
public SessionManager newSessionManager()
{
MongoSessionManager manager = (MongoSessionManager)super.newSessionManager();
manager.getSessionStore().setIdlePassivationTimeoutSec(idleSec);
return manager;
}
};
return server;
}
/**
* @see org.eclipse.jetty.server.session.AbstractIdleSessionTest#checkSessionIdled(java.lang.String)
*/
@Override
public void checkSessionIdled(String sessionId)
{
assertNotNull(_servlet);
assertNotNull(_servlet._session);
try (Lock lock = ((Session)_servlet._session).lock())
{
assertTrue(((Session)_servlet._session).isPassivated());
}
}
/**
* @see org.eclipse.jetty.server.session.AbstractIdleSessionTest#checkSessionDeIdled(java.lang.String)
*/
@Override
public void checkSessionDeIdled(String sessionId)
{
assertNotNull(_servlet);
assertNotNull(_servlet._session);
try (Lock lock = ((Session)_servlet._session).lock())
{
assertTrue(((Session)_servlet._session).isActive());
}
}
/**
* @see org.eclipse.jetty.server.session.AbstractIdleSessionTest#deleteSessionData(java.lang.String)
*/
@Override
public void deleteSessionData(String sessionId)
{
try
{
MongoTestServer.dropCollection();
}
catch (Exception e)
{
fail(e.getMessage());
}
}
}

View File

@ -19,6 +19,7 @@
package org.eclipse.jetty.nosql.mongodb;
import org.eclipse.jetty.server.SessionManager;
import org.eclipse.jetty.server.session.AbstractInvalidationSessionTest;
import org.eclipse.jetty.server.session.AbstractTestServer;
import org.junit.AfterClass;
@ -27,7 +28,7 @@ import org.junit.Test;
public class InvalidateSessionTest extends AbstractInvalidationSessionTest
{
public final static int IDLE_PASSIVATE_SEC = 1;
@BeforeClass
public static void beforeClass() throws Exception
@ -41,11 +42,26 @@ public class InvalidateSessionTest extends AbstractInvalidationSessionTest
{
MongoTestServer.dropCollection();
}
@Override
public AbstractTestServer createServer(int port)
public AbstractTestServer createServer(int port, int maxInterval, int inspectInterval)
{
return new MongoTestServer(port);
MongoTestServer server = new MongoTestServer(port, maxInterval, inspectInterval)
{
/**
* @see org.eclipse.jetty.nosql.mongodb.MongoTestServer#newSessionManager()
*/
@Override
public SessionManager newSessionManager()
{
MongoSessionManager manager = (MongoSessionManager)super.newSessionManager();
manager.getSessionStore().setIdlePassivationTimeoutSec(IDLE_PASSIVATE_SEC);
return manager;
}
};
return server;
}
@Override
@ -53,7 +69,7 @@ public class InvalidateSessionTest extends AbstractInvalidationSessionTest
{
try
{
Thread.sleep(2 * MongoTestServer.STALE_INTERVAL * 1000);
Thread.sleep(2 * IDLE_PASSIVATE_SEC * 1000);
}
catch (InterruptedException e)
{

View File

@ -22,10 +22,8 @@ import java.net.UnknownHostException;
import org.eclipse.jetty.server.SessionIdManager;
import org.eclipse.jetty.server.SessionManager;
import org.eclipse.jetty.server.session.AbstractSessionStore;
import org.eclipse.jetty.server.session.AbstractTestServer;
import org.eclipse.jetty.server.session.SessionHandler;
import org.eclipse.jetty.server.session.StalePeriodStrategy;
import com.mongodb.DBCollection;
import com.mongodb.Mongo;
@ -37,7 +35,6 @@ import com.mongodb.MongoException;
*/
public class MongoTestServer extends AbstractTestServer
{
public static final int STALE_INTERVAL = 1;
static int __workers=0;
@ -98,10 +95,7 @@ public class MongoTestServer extends AbstractTestServer
try
{
manager = new MongoSessionManager();
manager.getSessionDataStore().setGracePeriodSec(_scavengePeriod);
StalePeriodStrategy staleStrategy = new StalePeriodStrategy();
staleStrategy.setStaleSec(STALE_INTERVAL);
((AbstractSessionStore)manager.getSessionStore()).setStaleStrategy(staleStrategy);
manager.getSessionDataStore().setGracePeriodSec(_inspectionPeriod);
}
catch (Exception e)
{

View File

@ -0,0 +1,261 @@
//
// ========================================================================
// Copyright (c) 1995-2016 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.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.assertFalse;
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.HttpClient;
import org.eclipse.jetty.client.api.ContentResponse;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.server.SessionManager;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.StdErrLog;
import org.eclipse.jetty.util.thread.Locker.Lock;
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 abstract class AbstractIdleSessionTest
{
protected TestServlet _servlet = new TestServlet();
protected AbstractTestServer _server1 = null;
/**
* @param port
* @param max
* @param scavenge
* @param idleSec
* @return
*/
public abstract AbstractTestServer createServer (int port, int max, int scavenge, int idleSec);
/**
* @param sessionDir
* @param sessionId
*/
public abstract void checkSessionIdled (String sessionId);
/**
* @param sessionId
*/
public abstract void checkSessionDeIdled (String sessionId);
/**
* @param sessionId
*/
public abstract void deleteSessionData (String sessionId);
/**
* @param sec
*/
public void pause (int sec)
{
try
{
Thread.sleep(sec * 1000L);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
/**
* @throws Exception
*/
@Test
public void testSessionIdle() throws Exception
{
String contextPath = "";
String servletMapping = "/server";
int inactivePeriod = 20;
int scavengePeriod = 3;
int idlePeriod = 5;
((StdErrLog)Log.getLogger("org.eclipse.jetty.server.session")).setHideStacks(true);
System.setProperty("org.eclipse.jetty.STACKS", "false");
_server1 = createServer(0, inactivePeriod, scavengePeriod, idlePeriod);
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.start();
String url = "http://localhost:" + port1 + contextPath + servletMapping;
//make a request to set up a session on the server
ContentResponse response = client.GET(url + "?action=init");
assertEquals(HttpServletResponse.SC_OK,response.getStatus());
String sessionCookie = response.getHeaders().get("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(idlePeriod * 2);
//check that the session has been idled
checkSessionIdled(AbstractTestServer.extractSessionId(sessionCookie));
//make another request to de-idle the session
Request request = client.newRequest(url + "?action=test");
request.getHeaders().add("Cookie", sessionCookie);
ContentResponse response2 = request.send();
assertEquals(HttpServletResponse.SC_OK,response2.getStatus());
//check session de-idled
checkSessionDeIdled(AbstractTestServer.extractSessionId(sessionCookie));
//wait again for the session to be idled
pause(idlePeriod * 2);
//check that it is
checkSessionIdled(AbstractTestServer.extractSessionId(sessionCookie));
//While idle, take some action to ensure that a deidle won't work, like
//deleting all sessions in mongo
deleteSessionData(AbstractTestServer.extractSessionId(sessionCookie));
//make a request
request = client.newRequest(url + "?action=testfail");
request.getHeaders().add("Cookie", sessionCookie);
response2 = request.send();
assertEquals(HttpServletResponse.SC_OK,response2.getStatus());
//Test trying to de-idle an expired session (ie before the scavenger can get to it)
//make a request to set up a session on the server
response = client.GET(url + "?action=init");
assertEquals(HttpServletResponse.SC_OK,response.getStatus());
sessionCookie = response.getHeaders().get("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(idlePeriod * 2);
//stop the scavenger
if (_server1.getInspector() != null)
_server1.getInspector().stop();
//check that the session is idle
checkSessionIdled(AbstractTestServer.extractSessionId(sessionCookie));
//wait until the session should be expired
pause (inactivePeriod + (inactivePeriod/2));
//make another request to de-idle the session
request = client.newRequest(url + "?action=testfail");
request.getHeaders().add("Cookie", sessionCookie);
response2 = request.send();
assertEquals(HttpServletResponse.SC_OK,response2.getStatus());
}
finally
{
_server1.stop();
}
}
public static class TestServlet extends HttpServlet
{
public String originalId = null;
public HttpSession _session = 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("value", new Integer(1));
originalId = session.getId();
Session s = (Session)session;
try (Lock lock = s.lock())
{
assertTrue(!s.isPassivated());
}
_session = s;
}
else if ("test".equals(action))
{
HttpSession session = request.getSession(false);
assertTrue(session != null);
assertTrue(originalId.equals(session.getId()));
Session s = (Session)session;
try (Lock lock = s.lock();)
{
assertTrue(s.isActive());
assertFalse(s.isPassivated());
}
Integer v = (Integer)session.getAttribute("value");
session.setAttribute("value", new Integer(v.intValue()+1));
_session = session;
}
else if ("testfail".equals(action))
{
HttpSession session = request.getSession(false);
assertTrue(session == null);
_session = session;
}
}
}
}

View File

@ -43,7 +43,7 @@ import org.junit.Test;
*/
public abstract class AbstractInvalidationSessionTest
{
public abstract AbstractTestServer createServer(int port);
public abstract AbstractTestServer createServer(int port, int maxInactive, int inspectInterval);
public abstract void pause();
@Test
@ -51,7 +51,7 @@ public abstract class AbstractInvalidationSessionTest
{
String contextPath = "";
String servletMapping = "/server";
AbstractTestServer server1 = createServer(0);
AbstractTestServer server1 = createServer(0, 30, 1);
server1.addContext(contextPath).addServlet(TestServlet.class, servletMapping);
@ -59,7 +59,7 @@ public abstract class AbstractInvalidationSessionTest
{
server1.start();
int port1 = server1.getPort();
AbstractTestServer server2 = createServer(0);
AbstractTestServer server2 = createServer(0, 30, 1);
server2.addContext(contextPath).addServlet(TestServlet.class, servletMapping);
try

View File

@ -35,14 +35,14 @@ import org.eclipse.jetty.webapp.WebAppContext;
public abstract class AbstractTestServer
{
public static int DEFAULT_MAX_INACTIVE = 30;
public static int DEFAULT_SCAVENGE = 10;
public static int DEFAULT_INSPECTION_SEC = 10;
protected final Server _server;
protected final int _maxInactivePeriod;
protected final int _scavengePeriod;
protected final int _inspectionPeriod;
protected final ContextHandlerCollection _contexts;
protected SessionIdManager _sessionIdManager;
private PeriodicSessionInspector _scavenger;
private PeriodicSessionInspector _inspector;
@ -66,7 +66,7 @@ public abstract class AbstractTestServer
public AbstractTestServer(int port)
{
this(port, DEFAULT_MAX_INACTIVE, DEFAULT_SCAVENGE);
this(port, DEFAULT_MAX_INACTIVE, DEFAULT_INSPECTION_SEC);
}
public AbstractTestServer(int port, int maxInactivePeriod, int scavengePeriod)
@ -78,14 +78,14 @@ public abstract class AbstractTestServer
{
_server = new Server(port);
_maxInactivePeriod = maxInactivePeriod;
_scavengePeriod = scavengePeriod;
_inspectionPeriod = scavengePeriod;
_contexts = new ContextHandlerCollection();
_sessionIdManager = newSessionIdManager(sessionIdMgrConfig);
_server.setSessionIdManager(_sessionIdManager);
((AbstractSessionIdManager) _sessionIdManager).setServer(_server);
_scavenger = new PeriodicSessionInspector();
_scavenger.setIntervalSec(scavengePeriod);
((AbstractSessionIdManager)_sessionIdManager).setSessionScavenger(_scavenger);
_inspector = new PeriodicSessionInspector();
_inspector.setIntervalSec(scavengePeriod);
((AbstractSessionIdManager)_sessionIdManager).setSessionScavenger(_inspector);
}
@ -102,6 +102,11 @@ public abstract class AbstractTestServer
_server.start();
}
public PeriodicSessionInspector getInspector()
{
return _inspector;
}
public int getPort()
{
return ((NetworkConnector)getServer().getConnectors()[0]).getLocalPort();