|
|
@ -21,7 +21,6 @@ import java.security.Principal; |
|
|
|
import java.util.ArrayList; |
|
|
|
import java.util.ArrayList; |
|
|
|
import java.util.List; |
|
|
|
import java.util.List; |
|
|
|
import java.util.Map; |
|
|
|
import java.util.Map; |
|
|
|
|
|
|
|
|
|
|
|
import javax.servlet.ServletContext; |
|
|
|
import javax.servlet.ServletContext; |
|
|
|
import javax.servlet.http.HttpServletRequest; |
|
|
|
import javax.servlet.http.HttpServletRequest; |
|
|
|
import javax.servlet.http.HttpServletResponse; |
|
|
|
import javax.servlet.http.HttpServletResponse; |
|
|
@ -60,75 +59,59 @@ import org.springframework.web.socket.server.RequestUpgradeStrategy; |
|
|
|
* @author Phillip Webb |
|
|
|
* @author Phillip Webb |
|
|
|
* @author Rossen Stoyanchev |
|
|
|
* @author Rossen Stoyanchev |
|
|
|
* @author Brian Clozel |
|
|
|
* @author Brian Clozel |
|
|
|
|
|
|
|
* @author Juergen Hoeller |
|
|
|
* @since 4.0 |
|
|
|
* @since 4.0 |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public class JettyRequestUpgradeStrategy implements RequestUpgradeStrategy, Lifecycle, ServletContextAware { |
|
|
|
public class JettyRequestUpgradeStrategy implements RequestUpgradeStrategy, ServletContextAware, Lifecycle { |
|
|
|
|
|
|
|
|
|
|
|
private static final ThreadLocal<WebSocketHandlerContainer> wsContainerHolder = |
|
|
|
private static final ThreadLocal<WebSocketHandlerContainer> wsContainerHolder = |
|
|
|
new NamedThreadLocal<>("WebSocket Handler Container"); |
|
|
|
new NamedThreadLocal<>("WebSocket Handler Container"); |
|
|
|
|
|
|
|
|
|
|
|
// Actually 9.3.15+
|
|
|
|
private final WebSocketServerFactoryAdapter factoryAdapter = |
|
|
|
private static boolean isJetty94 = ClassUtils.hasConstructor(WebSocketServerFactory.class, ServletContext.class); |
|
|
|
(ClassUtils.hasConstructor(WebSocketServerFactory.class, ServletContext.class) ? |
|
|
|
|
|
|
|
new ModernJettyWebSocketServerFactoryAdapter() : new LegacyJettyWebSocketServerFactoryAdapter()); |
|
|
|
|
|
|
|
|
|
|
|
private WebSocketServerFactoryAdapter factoryAdapter; |
|
|
|
private ServletContext servletContext; |
|
|
|
|
|
|
|
|
|
|
|
private volatile List<WebSocketExtension> supportedExtensions; |
|
|
|
private volatile boolean running = false; |
|
|
|
|
|
|
|
|
|
|
|
protected ServletContext servletContext; |
|
|
|
private volatile List<WebSocketExtension> supportedExtensions; |
|
|
|
|
|
|
|
|
|
|
|
private volatile boolean running = false; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Default constructor that creates {@link WebSocketServerFactory} through |
|
|
|
* Default constructor that creates {@link WebSocketServerFactory} through |
|
|
|
* its default constructor thus using a default {@link WebSocketPolicy}. |
|
|
|
* its default constructor thus using a default {@link WebSocketPolicy}. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public JettyRequestUpgradeStrategy() { |
|
|
|
public JettyRequestUpgradeStrategy() { |
|
|
|
this(WebSocketPolicy.newServerPolicy()); |
|
|
|
this.factoryAdapter.setPolicy(WebSocketPolicy.newServerPolicy()); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* A constructor accepting a {@link WebSocketPolicy} |
|
|
|
* A constructor accepting a {@link WebSocketPolicy} to be used when |
|
|
|
* to be used when creating the {@link WebSocketServerFactory} instance. |
|
|
|
* creating the {@link WebSocketServerFactory} instance. |
|
|
|
* @since 4.3 |
|
|
|
* @param policy the policy to use |
|
|
|
|
|
|
|
* @since 4.3.5 |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public JettyRequestUpgradeStrategy(WebSocketPolicy webSocketPolicy) { |
|
|
|
public JettyRequestUpgradeStrategy(WebSocketPolicy policy) { |
|
|
|
this.factoryAdapter = isJetty94 ? new Jetty94WebSocketServerFactoryAdapter() |
|
|
|
Assert.notNull(policy, "WebSocketPolicy must not be null"); |
|
|
|
: new JettyWebSocketServerFactoryAdapter(); |
|
|
|
this.factoryAdapter.setPolicy(policy); |
|
|
|
this.factoryAdapter.setWebSocketPolicy(webSocketPolicy); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
/** |
|
|
|
public String[] getSupportedVersions() { |
|
|
|
* A constructor accepting a {@link WebSocketServerFactory}. |
|
|
|
return new String[] {String.valueOf(HandshakeRFC6455.VERSION)}; |
|
|
|
* @param factory the pre-configured factory to use |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public JettyRequestUpgradeStrategy(WebSocketServerFactory factory) { |
|
|
|
|
|
|
|
Assert.notNull(factory, "WebSocketServerFactory must not be null"); |
|
|
|
|
|
|
|
this.factoryAdapter.setFactory(factory); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
|
|
public List<WebSocketExtension> getSupportedExtensions(ServerHttpRequest request) { |
|
|
|
|
|
|
|
if (this.supportedExtensions == null) { |
|
|
|
|
|
|
|
this.supportedExtensions = getWebSocketExtensions(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return this.supportedExtensions; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private List<WebSocketExtension> getWebSocketExtensions() { |
|
|
|
|
|
|
|
List<WebSocketExtension> result = new ArrayList<>(); |
|
|
|
|
|
|
|
for (String name : this.factoryAdapter.getFactory().getExtensionFactory().getExtensionNames()) { |
|
|
|
|
|
|
|
result.add(new WebSocketExtension(name)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return result; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
public void setServletContext(ServletContext servletContext) { |
|
|
|
public void setServletContext(ServletContext servletContext) { |
|
|
|
this.servletContext = servletContext; |
|
|
|
this.servletContext = servletContext; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
|
|
public boolean isRunning() { |
|
|
|
|
|
|
|
return this.running; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
public void start() { |
|
|
|
public void start() { |
|
|
|
if (!isRunning()) { |
|
|
|
if (!isRunning()) { |
|
|
@ -136,7 +119,7 @@ public class JettyRequestUpgradeStrategy implements RequestUpgradeStrategy, Life |
|
|
|
try { |
|
|
|
try { |
|
|
|
this.factoryAdapter.start(); |
|
|
|
this.factoryAdapter.start(); |
|
|
|
} |
|
|
|
} |
|
|
|
catch (Exception ex) { |
|
|
|
catch (Throwable ex) { |
|
|
|
throw new IllegalStateException("Unable to start Jetty WebSocketServerFactory", ex); |
|
|
|
throw new IllegalStateException("Unable to start Jetty WebSocketServerFactory", ex); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -149,12 +132,39 @@ public class JettyRequestUpgradeStrategy implements RequestUpgradeStrategy, Life |
|
|
|
this.running = false; |
|
|
|
this.running = false; |
|
|
|
this.factoryAdapter.stop(); |
|
|
|
this.factoryAdapter.stop(); |
|
|
|
} |
|
|
|
} |
|
|
|
catch (Exception ex) { |
|
|
|
catch (Throwable ex) { |
|
|
|
throw new IllegalStateException("Unable to stop Jetty WebSocketServerFactory", ex); |
|
|
|
throw new IllegalStateException("Unable to stop Jetty WebSocketServerFactory", ex); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
|
|
public boolean isRunning() { |
|
|
|
|
|
|
|
return this.running; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
|
|
public String[] getSupportedVersions() { |
|
|
|
|
|
|
|
return new String[] { String.valueOf(HandshakeRFC6455.VERSION) }; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
|
|
public List<WebSocketExtension> getSupportedExtensions(ServerHttpRequest request) { |
|
|
|
|
|
|
|
if (this.supportedExtensions == null) { |
|
|
|
|
|
|
|
this.supportedExtensions = buildWebSocketExtensions(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return this.supportedExtensions; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private List<WebSocketExtension> buildWebSocketExtensions() { |
|
|
|
|
|
|
|
List<WebSocketExtension> result = new ArrayList<>(); |
|
|
|
|
|
|
|
for (String name : this.factoryAdapter.getFactory().getExtensionFactory().getExtensionNames()) { |
|
|
|
|
|
|
|
result.add(new WebSocketExtension(name)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return result; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
public void upgrade(ServerHttpRequest request, ServerHttpResponse response, |
|
|
|
public void upgrade(ServerHttpRequest request, ServerHttpResponse response, |
|
|
|
String selectedProtocol, List<WebSocketExtension> selectedExtensions, Principal user, |
|
|
|
String selectedProtocol, List<WebSocketExtension> selectedExtensions, Principal user, |
|
|
@ -197,7 +207,9 @@ public class JettyRequestUpgradeStrategy implements RequestUpgradeStrategy, Life |
|
|
|
|
|
|
|
|
|
|
|
private final List<ExtensionConfig> extensionConfigs; |
|
|
|
private final List<ExtensionConfig> extensionConfigs; |
|
|
|
|
|
|
|
|
|
|
|
public WebSocketHandlerContainer(JettyWebSocketHandlerAdapter handler, String protocol, List<WebSocketExtension> extensions) { |
|
|
|
public WebSocketHandlerContainer( |
|
|
|
|
|
|
|
JettyWebSocketHandlerAdapter handler, String protocol, List<WebSocketExtension> extensions) { |
|
|
|
|
|
|
|
|
|
|
|
this.handler = handler; |
|
|
|
this.handler = handler; |
|
|
|
this.selectedProtocol = protocol; |
|
|
|
this.selectedProtocol = protocol; |
|
|
|
if (CollectionUtils.isEmpty(extensions)) { |
|
|
|
if (CollectionUtils.isEmpty(extensions)) { |
|
|
@ -224,21 +236,29 @@ public class JettyRequestUpgradeStrategy implements RequestUpgradeStrategy, Life |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static abstract class WebSocketServerFactoryAdapter { |
|
|
|
private static abstract class WebSocketServerFactoryAdapter { |
|
|
|
|
|
|
|
|
|
|
|
protected WebSocketServerFactory factory; |
|
|
|
private WebSocketPolicy policy; |
|
|
|
|
|
|
|
|
|
|
|
protected WebSocketPolicy webSocketPolicy; |
|
|
|
private WebSocketServerFactory factory; |
|
|
|
|
|
|
|
|
|
|
|
public WebSocketServerFactory getFactory() { |
|
|
|
public void setPolicy(WebSocketPolicy policy) { |
|
|
|
return factory; |
|
|
|
this.policy = policy; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public void setWebSocketPolicy(WebSocketPolicy webSocketPolicy) { |
|
|
|
public void setFactory(WebSocketServerFactory factory) { |
|
|
|
this.webSocketPolicy = webSocketPolicy; |
|
|
|
this.factory = factory; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
protected void configureFactory() { |
|
|
|
public WebSocketServerFactory getFactory() { |
|
|
|
|
|
|
|
return this.factory; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public void start() throws Exception { |
|
|
|
|
|
|
|
if (this.factory == null) { |
|
|
|
|
|
|
|
this.factory = createFactory(this.policy); |
|
|
|
|
|
|
|
} |
|
|
|
this.factory.setCreator(new WebSocketCreator() { |
|
|
|
this.factory.setCreator(new WebSocketCreator() { |
|
|
|
@Override |
|
|
|
@Override |
|
|
|
public Object createWebSocket(ServletUpgradeRequest request, ServletUpgradeResponse response) { |
|
|
|
public Object createWebSocket(ServletUpgradeRequest request, ServletUpgradeResponse response) { |
|
|
@ -249,43 +269,60 @@ public class JettyRequestUpgradeStrategy implements RequestUpgradeStrategy, Life |
|
|
|
return container.getHandler(); |
|
|
|
return container.getHandler(); |
|
|
|
} |
|
|
|
} |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
startFactory(this.factory); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
abstract void start() throws Exception; |
|
|
|
public void stop() throws Exception { |
|
|
|
|
|
|
|
if (this.factory != null) { |
|
|
|
|
|
|
|
stopFactory(this.factory); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected abstract WebSocketServerFactory createFactory(WebSocketPolicy policy) throws Exception; |
|
|
|
|
|
|
|
|
|
|
|
abstract void stop() throws Exception; |
|
|
|
protected abstract void startFactory(WebSocketServerFactory factory) throws Exception; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected abstract void stopFactory(WebSocketServerFactory factory) throws Exception; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private class JettyWebSocketServerFactoryAdapter extends WebSocketServerFactoryAdapter { |
|
|
|
|
|
|
|
|
|
|
|
// Jetty 9.3.15+
|
|
|
|
|
|
|
|
private class ModernJettyWebSocketServerFactoryAdapter extends WebSocketServerFactoryAdapter { |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
void start() throws Exception { |
|
|
|
protected WebSocketServerFactory createFactory(WebSocketPolicy policy) throws Exception { |
|
|
|
this.factory = WebSocketServerFactory.class.getConstructor(WebSocketPolicy.class) |
|
|
|
servletContext.setAttribute(DecoratedObjectFactory.ATTR, new DecoratedObjectFactory()); |
|
|
|
.newInstance(this.webSocketPolicy); |
|
|
|
return new WebSocketServerFactory(servletContext, policy); |
|
|
|
configureFactory(); |
|
|
|
|
|
|
|
WebSocketServerFactory.class.getMethod("init", ServletContext.class) |
|
|
|
|
|
|
|
.invoke(this.factory, servletContext); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
void stop() throws Exception { |
|
|
|
protected void startFactory(WebSocketServerFactory factory) throws Exception { |
|
|
|
WebSocketServerFactory.class.getMethod("cleanup").invoke(this.factory); |
|
|
|
factory.start(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
|
|
protected void stopFactory(WebSocketServerFactory factory) throws Exception { |
|
|
|
|
|
|
|
factory.stop(); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private class Jetty94WebSocketServerFactoryAdapter extends WebSocketServerFactoryAdapter { |
|
|
|
|
|
|
|
|
|
|
|
// Jetty <9.3.15
|
|
|
|
|
|
|
|
private class LegacyJettyWebSocketServerFactoryAdapter extends WebSocketServerFactoryAdapter { |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
void start() throws Exception { |
|
|
|
protected WebSocketServerFactory createFactory(WebSocketPolicy policy) throws Exception { |
|
|
|
servletContext.setAttribute(DecoratedObjectFactory.ATTR, new DecoratedObjectFactory()); |
|
|
|
return WebSocketServerFactory.class.getConstructor(WebSocketPolicy.class).newInstance(policy); |
|
|
|
this.factory = new WebSocketServerFactory(servletContext, this.webSocketPolicy); |
|
|
|
} |
|
|
|
configureFactory(); |
|
|
|
|
|
|
|
this.factory.start(); |
|
|
|
@Override |
|
|
|
|
|
|
|
protected void startFactory(WebSocketServerFactory factory) throws Exception { |
|
|
|
|
|
|
|
WebSocketServerFactory.class.getMethod("init", ServletContext.class).invoke(factory, servletContext); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
void stop() throws Exception { |
|
|
|
protected void stopFactory(WebSocketServerFactory factory) throws Exception { |
|
|
|
this.factory.stop(); |
|
|
|
WebSocketServerFactory.class.getMethod("cleanup").invoke(factory); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|