Jetty 9.4.x 3722 session destroy listeners (#3723)

* Issue #3722 Use webapp classloader for HttpSessionListener.sessionDestroyed calls
This commit is contained in:
Jan Bartel 2019-06-03 10:27:38 +02:00 committed by GitHub
parent ad3be199e8
commit dec10044e0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 100 additions and 6 deletions

View File

@ -370,11 +370,22 @@ public class SessionHandler extends ScopedHandler
if (_sessionListeners!=null)
{
HttpSessionEvent event=new HttpSessionEvent(session);
for (int i = _sessionListeners.size()-1; i>=0; i--)
//We annoint the calling thread with
//the webapp's classloader because the calling thread may
//come from the scavenger, rather than a request thread
Runnable r = new Runnable()
{
_sessionListeners.get(i).sessionDestroyed(event);
}
@Override
public void run ()
{
HttpSessionEvent event=new HttpSessionEvent(session);
for (int i = _sessionListeners.size()-1; i>=0; i--)
{
_sessionListeners.get(i).sessionDestroyed(event);
}
}
};
_sessionContext.run(r);
}
}

View File

@ -0,0 +1,61 @@
//
// ========================================================================
// Copyright (c) 1995-2019 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 javax.servlet.http.HttpSessionEvent;
/**
* TestHttpSessionListenerWithWebappClasses
*
* A session listener class that checks that sessionDestroyed
* events can reference classes known only to the webapp, ie
* that the calling thread has been correctly annointed with
* the webapp loader.
*
*/
public class TestHttpSessionListenerWithWebappClasses extends TestHttpSessionListener
{
public TestHttpSessionListenerWithWebappClasses()
{
super();
}
public TestHttpSessionListenerWithWebappClasses(boolean access)
{
super(access);
}
@Override
public void sessionDestroyed(HttpSessionEvent se)
{
//try loading a class that is known only to the webapp
//to test that the calling thread has been properly
//annointed with the webapp's classloader
try
{
Class<?> clazz = Thread.currentThread().getContextClassLoader().loadClass("Foo");
}
catch (Exception cnfe)
{
ex=cnfe;
}
super.sessionDestroyed(se);
}
}

View File

@ -18,9 +18,14 @@
package org.eclipse.jetty.server.session;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.net.HttpCookie;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.concurrent.TimeUnit;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
@ -35,6 +40,8 @@ import org.eclipse.jetty.client.api.ContentResponse;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.toolchain.test.IO;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
@ -121,13 +128,27 @@ public class SessionListenerTest
/**
* Test that listeners are called when a session expires.
* Test that listeners are called when a session expires
* and that the listener is able to access webapp classes.
*
* @throws Exception
*/
@Test
public void testSessionExpiresWithListener() throws Exception
{
//Use a class that would only be known to the webapp classloader
InputStream foostream = Thread.currentThread().getContextClassLoader().getResourceAsStream("Foo.clazz");
File foodir = new File (MavenTestingUtils.getTargetDir(), "foo");
foodir.mkdirs();
File fooclass = new File (foodir, "Foo.class");
IO.copy(foostream, new FileOutputStream(fooclass));
assertTrue(fooclass.exists());
assertTrue(fooclass.length() != 0);
URL[] foodirUrls = new URL[]{foodir.toURI().toURL()};
URLClassLoader contextClassLoader = new URLClassLoader(foodirUrls, Thread.currentThread().getContextClassLoader());
String contextPath = "/";
String servletMapping = "/server";
int inactivePeriod = 3;
@ -143,8 +164,9 @@ public class SessionListenerTest
TestServlet servlet = new TestServlet();
ServletHolder holder = new ServletHolder(servlet);
ServletContextHandler context = server1.addContext(contextPath);
context.setClassLoader(contextClassLoader);
context.addServlet(holder, servletMapping);
TestHttpSessionListener listener = new TestHttpSessionListener(true);
TestHttpSessionListener listener = new TestHttpSessionListenerWithWebappClasses(true);
context.getSessionHandler().addEventListener(listener);
server1.start();