442495 - Bad Context ClassLoader in JSR356 WebSocket onOpen

+ Fixing onOpen context classloader to be that of the context
  that started the WebSocketUpgradeFilter (which will be the
  same as the WebAppContext in most cases)
This commit is contained in:
Joakim Erdfelt 2014-09-22 14:37:00 -07:00
parent d6082b2d65
commit 0dca1b0794
4 changed files with 114 additions and 85 deletions

View File

@ -131,8 +131,13 @@ public class WebSocketServerContainerInitializer implements ServletContainerInit
ServletContextHandler jettyContext = (ServletContextHandler)handler; ServletContextHandler jettyContext = (ServletContextHandler)handler;
ClassLoader old = Thread.currentThread().getContextClassLoader();
try
{
Thread.currentThread().setContextClassLoader(context.getClassLoader());
// Create the Jetty ServerContainer implementation // Create the Jetty ServerContainer implementation
ServerContainer jettyContainer = configureContext(context, jettyContext); ServerContainer jettyContainer = configureContext(context,jettyContext);
// Store a reference to the ServerContainer per javax.websocket spec 1.0 final section 6.4 Programmatic Server Deployment // Store a reference to the ServerContainer per javax.websocket spec 1.0 final section 6.4 Programmatic Server Deployment
context.setAttribute(javax.websocket.server.ServerContainer.class.getName(),jettyContainer); context.setAttribute(javax.websocket.server.ServerContainer.class.getName(),jettyContainer);
@ -231,6 +236,9 @@ public class WebSocketServerContainerInitializer implements ServletContainerInit
throw new ServletException(e); throw new ServletException(e);
} }
} }
} finally {
Thread.currentThread().setContextClassLoader(old);
}
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")

View File

@ -61,6 +61,7 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Inc
private final LogicalConnection connection; private final LogicalConnection connection;
private final SessionListener[] sessionListeners; private final SessionListener[] sessionListeners;
private final Executor executor; private final Executor executor;
private ClassLoader classLoader;
private ExtensionFactory extensionFactory; private ExtensionFactory extensionFactory;
private String protocolVersion; private String protocolVersion;
private Map<String, String[]> parameterMap = new HashMap<>(); private Map<String, String[]> parameterMap = new HashMap<>();
@ -78,6 +79,7 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Inc
throw new RuntimeException("Request URI cannot be null"); throw new RuntimeException("Request URI cannot be null");
} }
this.classLoader = Thread.currentThread().getContextClassLoader();
this.requestURI = requestURI; this.requestURI = requestURI;
this.websocket = websocket; this.websocket = websocket;
this.connection = connection; this.connection = connection;
@ -183,6 +185,11 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Inc
return this.connection.getBufferPool(); return this.connection.getBufferPool();
} }
public ClassLoader getClassLoader()
{
return this.getClass().getClassLoader();
}
public LogicalConnection getConnection() public LogicalConnection getConnection()
{ {
return connection; return connection;
@ -394,14 +401,16 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Inc
return; return;
} }
ClassLoader old = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(classLoader);
// Upgrade success // Upgrade success
connection.getIOState().onConnected(); connection.getIOState().onConnected();
// Connect remote // Connect remote
remote = new WebSocketRemoteEndpoint(connection,outgoingHandler,getBatchMode()); remote = new WebSocketRemoteEndpoint(connection,outgoingHandler,getBatchMode());
try
{
// Open WebSocket // Open WebSocket
websocket.openSession(this); websocket.openSession(this);
@ -425,6 +434,10 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Inc
close(statusCode,t.getMessage()); close(statusCode,t.getMessage());
} }
finally
{
Thread.currentThread().setContextClassLoader(old);
}
} }
public void setExtensionFactory(ExtensionFactory extensionFactory) public void setExtensionFactory(ExtensionFactory extensionFactory)
@ -506,4 +519,5 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Inc
builder.append("]"); builder.append("]");
return builder.toString(); return builder.toString();
} }
} }

View File

@ -30,6 +30,7 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
@ -70,6 +71,7 @@ public class WebSocketServerFactory extends ContainerLifeCycle implements WebSoc
{ {
private static final Logger LOG = Log.getLogger(WebSocketServerFactory.class); private static final Logger LOG = Log.getLogger(WebSocketServerFactory.class);
private final ClassLoader contextClassloader;
private final Map<Integer, WebSocketHandshake> handshakes = new HashMap<>(); private final Map<Integer, WebSocketHandshake> handshakes = new HashMap<>();
/** /**
* Have the factory maintain 1 and only 1 scheduler. All connections share this scheduler. * Have the factory maintain 1 and only 1 scheduler. All connections share this scheduler.
@ -107,6 +109,8 @@ public class WebSocketServerFactory extends ContainerLifeCycle implements WebSoc
addBean(scheduler); addBean(scheduler);
addBean(bufferPool); addBean(bufferPool);
this.contextClassloader = Thread.currentThread().getContextClassLoader();
this.registeredSocketClasses = new ArrayList<>(); this.registeredSocketClasses = new ArrayList<>();
this.defaultPolicy = policy; this.defaultPolicy = policy;
@ -151,8 +155,10 @@ public class WebSocketServerFactory extends ContainerLifeCycle implements WebSoc
@Override @Override
public boolean acceptWebSocket(WebSocketCreator creator, HttpServletRequest request, HttpServletResponse response) throws IOException public boolean acceptWebSocket(WebSocketCreator creator, HttpServletRequest request, HttpServletResponse response) throws IOException
{ {
ClassLoader old = Thread.currentThread().getContextClassLoader();
try try
{ {
Thread.currentThread().setContextClassLoader(contextClassloader);
ServletUpgradeRequest sockreq = new ServletUpgradeRequest(request); ServletUpgradeRequest sockreq = new ServletUpgradeRequest(request);
ServletUpgradeResponse sockresp = new ServletUpgradeResponse(response); ServletUpgradeResponse sockresp = new ServletUpgradeResponse(response);
@ -182,6 +188,10 @@ public class WebSocketServerFactory extends ContainerLifeCycle implements WebSoc
{ {
throw new IOException("Unable to accept websocket due to mangled URI", e); throw new IOException("Unable to accept websocket due to mangled URI", e);
} }
finally
{
Thread.currentThread().setContextClassLoader(old);
}
} }
public void addSessionFactory(SessionFactory sessionFactory) public void addSessionFactory(SessionFactory sessionFactory)

View File

@ -91,10 +91,7 @@ public class WebSocketUpgradeFilter extends ContainerLifeCycle implements Filter
String pathSpec = "/*"; String pathSpec = "/*";
EnumSet<DispatcherType> dispatcherTypes = EnumSet.of(DispatcherType.REQUEST); EnumSet<DispatcherType> dispatcherTypes = EnumSet.of(DispatcherType.REQUEST);
boolean isMatchAfter = false; boolean isMatchAfter = false;
String urlPatterns[] = String urlPatterns[] = { pathSpec };
{
pathSpec
};
FilterRegistration.Dynamic dyn = context.addFilter(name,filter); FilterRegistration.Dynamic dyn = context.addFilter(name,filter);
dyn.addMappingForUrlPatterns(dispatcherTypes,isMatchAfter,urlPatterns); dyn.addMappingForUrlPatterns(dispatcherTypes,isMatchAfter,urlPatterns);