Merge remote-tracking branch 'origin/jetty-9.4.x' into jetty-10.0.x
This commit is contained in:
commit
506e4dc682
|
@ -476,9 +476,7 @@
|
|||
<systemPropertyVariables>
|
||||
<mavenRepoPath>${settings.localRepository}</mavenRepoPath>
|
||||
</systemPropertyVariables>
|
||||
<excludes>
|
||||
<exclude>**/TestJettyOSGiBootHTTP2</exclude>
|
||||
</excludes>
|
||||
<argLine>-Dconscrypt-version=${conscrypt.version}</argLine>
|
||||
</configuration>
|
||||
<!-- paxexam still using junit 4 so we have to force the provider here -->
|
||||
<dependencies>
|
||||
|
|
|
@ -100,9 +100,9 @@ public class TestJettyOSGiBootHTTP2Conscrypt
|
|||
res.add(CoreOptions.systemProperty("jetty.alpn.protocols").value("h2,http/1.1"));
|
||||
res.add(CoreOptions.systemProperty("jetty.sslContext.provider").value("Conscrypt"));
|
||||
|
||||
res.add(wrappedBundle(mavenBundle().groupId("org.conscrypt").artifactId("conscrypt-openjdk-uber").version("1.1.4"))
|
||||
res.add(wrappedBundle(mavenBundle().groupId("org.conscrypt").artifactId("conscrypt-openjdk-uber").versionAsInProject())
|
||||
.imports("javax.net.ssl,*")
|
||||
.exports("org.conscrypt;version=1.1.4")
|
||||
.exports("org.conscrypt;version="+System.getProperty("conscrypt-version"))
|
||||
.instructions("Bundle-NativeCode=META-INF/native/libconscrypt_openjdk_jni-linux-x86_64.so")
|
||||
.start());
|
||||
res.add(mavenBundle().groupId("org.eclipse.jetty.osgi").artifactId("jetty-osgi-alpn").versionAsInProject().noStart());
|
||||
|
|
|
@ -151,8 +151,9 @@ public abstract class AbstractSessionCache extends ContainerLifeCycle implements
|
|||
|
||||
/**
|
||||
* Remove the session with this identity from the store
|
||||
*
|
||||
* @param id the id
|
||||
* @return true if removed false otherwise
|
||||
* @return Session that was removed or null
|
||||
*/
|
||||
public abstract Session doDelete (String id);
|
||||
|
||||
|
@ -727,12 +728,8 @@ public abstract class AbstractSessionCache extends ContainerLifeCycle implements
|
|||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @see org.eclipse.jetty.server.session.SessionCache#renewSessionId(java.lang.String, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public Session renewSessionId (String oldId, String newId)
|
||||
public Session renewSessionId (String oldId, String newId, String oldExtendedId, String newExtendedId)
|
||||
throws Exception
|
||||
{
|
||||
if (StringUtil.isBlank(oldId))
|
||||
|
@ -741,17 +738,40 @@ public abstract class AbstractSessionCache extends ContainerLifeCycle implements
|
|||
throw new IllegalArgumentException ("New session id is null");
|
||||
|
||||
Session session = get(oldId);
|
||||
if (session == null)
|
||||
return null;
|
||||
renewSessionId(session, newId, newExtendedId);
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Swap the id on a session.
|
||||
*
|
||||
* @param session the session for which to do the swap
|
||||
* @param newId the new id
|
||||
* @param newExtendedId the full id plus node id
|
||||
*
|
||||
* @throws Exception if there was a failure saving the change
|
||||
*/
|
||||
protected void renewSessionId (Session session, String newId, String newExtendedId)
|
||||
throws Exception
|
||||
{
|
||||
if (session == null)
|
||||
return;
|
||||
|
||||
try (Lock lock = session.lock())
|
||||
{
|
||||
String oldId = session.getId();
|
||||
session.checkValidForWrite(); //can't change id on invalid session
|
||||
session.getSessionData().setId(newId);
|
||||
session.getSessionData().setLastSaved(0); //pretend that the session has never been saved before to get a full save
|
||||
session.getSessionData().setDirty(true); //ensure we will try to write the session out
|
||||
session.getSessionData().setDirty(true); //ensure we will try to write the session out
|
||||
session.setExtendedId(newExtendedId); //remember the new extended id
|
||||
session.setIdChanged(true); //session id changed
|
||||
|
||||
doPutIfAbsent(newId, session); //put the new id into our map
|
||||
doDelete (oldId); //take old out of map
|
||||
|
||||
if (_sessionDataStore != null)
|
||||
{
|
||||
_sessionDataStore.delete(oldId); //delete the session data with the old id
|
||||
|
@ -759,7 +779,6 @@ public abstract class AbstractSessionCache extends ContainerLifeCycle implements
|
|||
}
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug ("Session id {} swapped for new id {}", oldId, newId);
|
||||
return session;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -91,16 +91,41 @@ public interface SessionCache extends LifeCycle
|
|||
*/
|
||||
Session newSession (SessionData data);
|
||||
|
||||
/**
|
||||
* Change the id of a session.
|
||||
*
|
||||
* This method has been superceded by the 4 arg renewSessionId method and
|
||||
* should no longer be called.
|
||||
*
|
||||
* @param oldId the old id
|
||||
* @param newId the new id
|
||||
* @return the changed Session
|
||||
* @throws Exception if anything went wrong
|
||||
* @deprecated use
|
||||
* {@link #renewSessionId(String oldId, String newId, String oldExtendedId, String newExtendedId)}
|
||||
*/
|
||||
@Deprecated
|
||||
default Session renewSessionId(String oldId, String newId) throws Exception
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Change the id of a Session.
|
||||
*
|
||||
* @param oldId the current session id
|
||||
* @param newId the new session id
|
||||
* @param oldExtendedId the current extended session id
|
||||
* @param newExtendedId the new extended session id
|
||||
* @return the Session after changing its id
|
||||
* @throws Exception if any error occurred
|
||||
*/
|
||||
Session renewSessionId (String oldId, String newId) throws Exception;
|
||||
default Session renewSessionId(String oldId, String newId, String oldExtendedId, String newExtendedId) throws Exception
|
||||
{
|
||||
return renewSessionId(oldId, newId);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
|
||||
package org.eclipse.jetty.server.session;
|
||||
|
||||
import static java.lang.Math.round;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
@ -65,8 +67,6 @@ import org.eclipse.jetty.util.thread.Locker.Lock;
|
|||
import org.eclipse.jetty.util.thread.ScheduledExecutorScheduler;
|
||||
import org.eclipse.jetty.util.thread.Scheduler;
|
||||
|
||||
import static java.lang.Math.round;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* SessionHandler.
|
||||
|
@ -343,6 +343,60 @@ public class SessionHandler extends ScopedHandler
|
|||
_sessionListeners.clear();
|
||||
_sessionIdListeners.clear();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Call the session lifecycle listeners
|
||||
* @param session the session on which to call the lifecycle listeners
|
||||
*/
|
||||
protected void callSessionDestroyedListeners (Session session)
|
||||
{
|
||||
if (session == null)
|
||||
return;
|
||||
|
||||
if (_sessionListeners!=null)
|
||||
{
|
||||
HttpSessionEvent event=new HttpSessionEvent(session);
|
||||
for (int i = _sessionListeners.size()-1; i>=0; i--)
|
||||
{
|
||||
_sessionListeners.get(i).sessionDestroyed(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Call the session lifecycle listeners
|
||||
* @param session the session on which to call the lifecycle listeners
|
||||
*/
|
||||
protected void callSessionCreatedListeners (Session session)
|
||||
{
|
||||
if (session == null)
|
||||
return;
|
||||
|
||||
if (_sessionListeners!=null)
|
||||
{
|
||||
HttpSessionEvent event=new HttpSessionEvent(session);
|
||||
for (int i = _sessionListeners.size()-1; i>=0; i--)
|
||||
{
|
||||
_sessionListeners.get(i).sessionCreated(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected void callSessionIdListeners (Session session, String oldId)
|
||||
{
|
||||
//inform the listeners
|
||||
if (!_sessionIdListeners.isEmpty())
|
||||
{
|
||||
HttpSessionEvent event = new HttpSessionEvent(session);
|
||||
for (HttpSessionIdListener l:_sessionIdListeners)
|
||||
{
|
||||
l.sessionIdChanged(event, oldId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
|
@ -793,15 +847,10 @@ public class SessionHandler extends ScopedHandler
|
|||
_sessionCache.put(id, session);
|
||||
_sessionsCreatedStats.increment();
|
||||
|
||||
if (request.isSecure())
|
||||
if (request!=null && request.isSecure())
|
||||
session.setAttribute(Session.SESSION_CREATED_SECURE, Boolean.TRUE);
|
||||
|
||||
if (_sessionListeners!=null)
|
||||
{
|
||||
HttpSessionEvent event=new HttpSessionEvent(session);
|
||||
for (HttpSessionListener listener : _sessionListeners)
|
||||
listener.sessionCreated(event);
|
||||
}
|
||||
callSessionCreatedListeners(session);
|
||||
|
||||
return session;
|
||||
}
|
||||
|
@ -1183,24 +1232,15 @@ public class SessionHandler extends ScopedHandler
|
|||
{
|
||||
try
|
||||
{
|
||||
Session session = _sessionCache.renewSessionId (oldId, newId); //swap the id over
|
||||
Session session = _sessionCache.renewSessionId (oldId, newId, oldExtendedId, newExtendedId); //swap the id over
|
||||
if (session == null)
|
||||
{
|
||||
//session doesn't exist on this context
|
||||
return;
|
||||
}
|
||||
|
||||
session.setExtendedId(newExtendedId); //remember the extended id
|
||||
|
||||
//inform the listeners
|
||||
if (!_sessionIdListeners.isEmpty())
|
||||
{
|
||||
HttpSessionEvent event = new HttpSessionEvent(session);
|
||||
for (HttpSessionIdListener l:_sessionIdListeners)
|
||||
{
|
||||
l.sessionIdChanged(event, oldId);
|
||||
}
|
||||
}
|
||||
callSessionIdListeners(session, oldId);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
@ -1208,28 +1248,62 @@ public class SessionHandler extends ScopedHandler
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Record length of time session has been active. Called when the
|
||||
* session is about to be invalidated.
|
||||
*
|
||||
* @param session the session whose time to record
|
||||
*/
|
||||
protected void recordSessionTime (Session session)
|
||||
{
|
||||
_sessionTimeStats.record(round((System.currentTimeMillis() - session.getSessionData().getCreated())/1000.0));
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* Called when a session has expired.
|
||||
* Called by SessionIdManager to remove a session that has been invalidated,
|
||||
* either by this context or another context. Also called by
|
||||
* SessionIdManager when a session has expired in either this context or
|
||||
* another context.
|
||||
*
|
||||
* @param id the id to invalidate
|
||||
* @param id the session id to invalidate
|
||||
*/
|
||||
public void invalidate (String id)
|
||||
{
|
||||
|
||||
if (StringUtil.isBlank(id))
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
//remove the session and call the destroy listeners
|
||||
Session session = removeSession(id, true);
|
||||
|
||||
{
|
||||
// Remove the Session object from the session cache and any backing
|
||||
// data store
|
||||
Session session = _sessionCache.delete(id);
|
||||
if (session != null)
|
||||
{
|
||||
_sessionTimeStats.record(round((System.currentTimeMillis() - session.getSessionData().getCreated())/1000.0));
|
||||
session.finishInvalidate();
|
||||
//start invalidating if it is not already begun, and call the listeners
|
||||
try
|
||||
{
|
||||
if (session.beginInvalidate())
|
||||
{
|
||||
try
|
||||
{
|
||||
callSessionDestroyedListeners(session);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn("Session listener threw exception", e);
|
||||
}
|
||||
//call the attribute removed listeners and finally mark it as invalid
|
||||
session.finishInvalidate();
|
||||
}
|
||||
}
|
||||
catch (IllegalStateException e)
|
||||
{
|
||||
if (LOG.isDebugEnabled()) LOG.debug("Session {} already invalid", session);
|
||||
LOG.ignore(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
|
|
|
@ -99,7 +99,7 @@ public interface Dumpable
|
|||
}
|
||||
catch (Throwable th)
|
||||
{
|
||||
out.append("=>").append(th.toString()).append("\n");
|
||||
out.append("=> ").append(th.toString()).append("\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -133,12 +133,12 @@ public interface Dumpable
|
|||
for (Iterator<Object> i = container.getBeans().iterator(); i.hasNext();)
|
||||
{
|
||||
Object bean = i.next();
|
||||
String nextIndent = indent + ((i.hasNext() || size>0) ? "| " : " ");
|
||||
String nextIndent = indent + ((i.hasNext() || size>0) ? "| " : " ");
|
||||
if (bean instanceof LifeCycle)
|
||||
{
|
||||
if (container.isManaged(bean))
|
||||
{
|
||||
out.append(indent).append("+=");
|
||||
out.append(indent).append("+= ");
|
||||
if (bean instanceof Dumpable)
|
||||
((Dumpable)bean).dump(out,nextIndent);
|
||||
else
|
||||
|
@ -146,7 +146,7 @@ public interface Dumpable
|
|||
}
|
||||
else if (containerLifeCycle != null && containerLifeCycle.isAuto(bean))
|
||||
{
|
||||
out.append(indent).append("+?");
|
||||
out.append(indent).append("+? ");
|
||||
if (bean instanceof Dumpable)
|
||||
((Dumpable)bean).dump(out,nextIndent);
|
||||
else
|
||||
|
@ -154,18 +154,18 @@ public interface Dumpable
|
|||
}
|
||||
else
|
||||
{
|
||||
out.append(indent).append("+~");
|
||||
out.append(indent).append("+~ ");
|
||||
dumpObject(out, bean);
|
||||
}
|
||||
}
|
||||
else if (containerLifeCycle != null && containerLifeCycle.isUnmanaged(bean))
|
||||
{
|
||||
out.append(indent).append("+~");
|
||||
out.append(indent).append("+~ ");
|
||||
dumpObject(out, bean);
|
||||
}
|
||||
else
|
||||
{
|
||||
out.append(indent).append("+-");
|
||||
out.append(indent).append("+- ");
|
||||
if (bean instanceof Dumpable)
|
||||
((Dumpable)bean).dump(out,nextIndent);
|
||||
else
|
||||
|
@ -178,8 +178,8 @@ public interface Dumpable
|
|||
for (Iterator i = ((Iterable<?>)object).iterator(); i.hasNext();)
|
||||
{
|
||||
Object item = i.next();
|
||||
String nextIndent = indent + ((i.hasNext() || size>0) ? "| " : " ");
|
||||
out.append(indent).append("+:");
|
||||
String nextIndent = indent + ((i.hasNext() || size>0) ? "| " : " ");
|
||||
out.append(indent).append("+: ");
|
||||
if (item instanceof Dumpable)
|
||||
((Dumpable)item).dump(out,nextIndent);
|
||||
else
|
||||
|
@ -191,8 +191,8 @@ public interface Dumpable
|
|||
for (Iterator<? extends Map.Entry<?, ?>> i = ((Map<?,?>)object).entrySet().iterator(); i.hasNext();)
|
||||
{
|
||||
Map.Entry entry = i.next();
|
||||
String nextIndent = indent + ((i.hasNext() || size>0) ? "| " : " ");
|
||||
out.append(indent).append("+@").append(String.valueOf(entry.getKey())).append('=');
|
||||
String nextIndent = indent + ((i.hasNext() || size>0) ? "| " : " ");
|
||||
out.append(indent).append("+@ ").append(String.valueOf(entry.getKey())).append('=');
|
||||
Object item = entry.getValue();
|
||||
if (item instanceof Dumpable)
|
||||
((Dumpable)item).dump(out,nextIndent);
|
||||
|
@ -208,13 +208,12 @@ public interface Dumpable
|
|||
for (Object item : extraChildren)
|
||||
{
|
||||
i++;
|
||||
String nextIndent = indent + (i<size ? "| " : " ");
|
||||
out.append(indent).append("+>");
|
||||
String nextIndent = indent + (i<size ? "| " : " ");
|
||||
out.append(indent).append("+> ");
|
||||
if (item instanceof Dumpable)
|
||||
((Dumpable)item).dump(out,nextIndent);
|
||||
else
|
||||
dumpObjects(out, nextIndent, item);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -34,7 +34,9 @@ import java.util.concurrent.TimeUnit;
|
|||
import javax.servlet.http.HttpSessionActivationListener;
|
||||
import javax.servlet.http.HttpSessionEvent;
|
||||
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.SessionIdManager;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
|
@ -65,6 +67,100 @@ public class DefaultSessionCacheTest
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRenewIdMultipleRequests() throws Exception
|
||||
{
|
||||
//Test that invalidation happens on ALL copies of the session that are in-use by requests
|
||||
Server server = new Server();
|
||||
|
||||
SessionIdManager sessionIdManager = new DefaultSessionIdManager(server);
|
||||
server.setSessionIdManager(sessionIdManager);
|
||||
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
|
||||
context.setContextPath("/test");
|
||||
context.setServer(server);
|
||||
context.getSessionHandler().setMaxInactiveInterval((int)TimeUnit.DAYS.toSeconds(1));
|
||||
context.getSessionHandler().setSessionIdManager(sessionIdManager);
|
||||
|
||||
DefaultSessionCacheFactory cacheFactory = new DefaultSessionCacheFactory();
|
||||
cacheFactory.setSaveOnCreate(true); //ensures that a session is persisted as soon as it is created
|
||||
|
||||
DefaultSessionCache cache = (DefaultSessionCache)cacheFactory.getSessionCache(context.getSessionHandler());
|
||||
|
||||
TestSessionDataStore store = new TestSessionDataStore();
|
||||
cache.setSessionDataStore(store);
|
||||
context.getSessionHandler().setSessionCache(cache);
|
||||
TestHttpSessionListener listener = new TestHttpSessionListener();
|
||||
context.getSessionHandler().addEventListener(listener);
|
||||
|
||||
server.setHandler(context);
|
||||
try
|
||||
{
|
||||
server.start();
|
||||
|
||||
//create a new session
|
||||
Session s = (Session)context.getSessionHandler().newHttpSession(null);
|
||||
String id = s.getId();
|
||||
context.getSessionHandler().access(s, false); //simulate accessing the request
|
||||
context.getSessionHandler().complete(s); //simulate completing the request
|
||||
|
||||
//make 1st request
|
||||
final Session session = context.getSessionHandler().getSession(id); //get the session again
|
||||
assertNotNull(session);
|
||||
context.getSessionHandler().access(session, false); //simulate accessing the request
|
||||
|
||||
|
||||
|
||||
//make 2nd request
|
||||
final Session session2 = context.getSessionHandler().getSession(id); //get the session again
|
||||
context.getSessionHandler().access(session2, false); //simulate accessing the request
|
||||
assertNotNull(session2);
|
||||
assertTrue(session == session2);
|
||||
|
||||
|
||||
|
||||
Thread t2 = new Thread(new Runnable()
|
||||
{
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
System.err.println("Starting session id renewal");
|
||||
session2.renewId(new Request(null,null));
|
||||
System.err.println("Finished session id renewal");
|
||||
}
|
||||
});
|
||||
t2.start();
|
||||
|
||||
|
||||
|
||||
Thread t = new Thread(new Runnable()
|
||||
{
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
System.err.println("Starting invalidation");
|
||||
try{Thread.sleep(1000L);}catch (Exception e) {e.printStackTrace();}
|
||||
session.invalidate();
|
||||
System.err.println("Finished invalidation");
|
||||
}
|
||||
}
|
||||
);
|
||||
t.start();
|
||||
|
||||
t.join();
|
||||
t2.join();
|
||||
|
||||
}
|
||||
finally
|
||||
{
|
||||
server.stop();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Test sessions are saved when shutdown with a store.
|
||||
|
@ -180,7 +276,7 @@ public class DefaultSessionCacheTest
|
|||
cache.put("1234", session);
|
||||
assertTrue(cache.contains("1234"));
|
||||
|
||||
cache.renewSessionId("1234", "5678");
|
||||
cache.renewSessionId("1234", "5678", "1234.foo", "5678.foo");
|
||||
|
||||
assertTrue(cache.contains("5678"));
|
||||
assertFalse(cache.contains("1234"));
|
||||
|
|
Loading…
Reference in New Issue