Thread-safe access to WebSocketServerFactory and WebSocketExtensions
See gh-24745
This commit is contained in:
parent
b7b36891fb
commit
fd1ca46ca1
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2019 the original author or authors.
|
* Copyright 2002-2020 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -20,6 +20,7 @@ import java.io.IOException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.security.Principal;
|
import java.security.Principal;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
@ -72,7 +73,7 @@ public class JettyRequestUpgradeStrategy implements RequestUpgradeStrategy, Serv
|
||||||
private WebSocketPolicy policy;
|
private WebSocketPolicy policy;
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private WebSocketServerFactory factory;
|
private volatile WebSocketServerFactory factory;
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private ServletContext servletContext;
|
private ServletContext servletContext;
|
||||||
|
@ -122,17 +123,20 @@ public class JettyRequestUpgradeStrategy implements RequestUpgradeStrategy, Serv
|
||||||
if (!isRunning()) {
|
if (!isRunning()) {
|
||||||
this.running = true;
|
this.running = true;
|
||||||
try {
|
try {
|
||||||
if (this.factory == null) {
|
WebSocketServerFactory factory = this.factory;
|
||||||
this.factory = new WebSocketServerFactory(this.servletContext, this.policy);
|
if (factory == null) {
|
||||||
|
Assert.state(this.servletContext != null, "No ServletContext set");
|
||||||
|
factory = new WebSocketServerFactory(this.servletContext, this.policy);
|
||||||
|
this.factory = factory;
|
||||||
}
|
}
|
||||||
this.factory.setCreator((request, response) -> {
|
factory.setCreator((request, response) -> {
|
||||||
WebSocketHandlerContainer container = containerHolder.get();
|
WebSocketHandlerContainer container = containerHolder.get();
|
||||||
Assert.state(container != null, "Expected WebSocketHandlerContainer");
|
Assert.state(container != null, "Expected WebSocketHandlerContainer");
|
||||||
response.setAcceptedSubProtocol(container.getSelectedProtocol());
|
response.setAcceptedSubProtocol(container.getSelectedProtocol());
|
||||||
response.setExtensions(container.getExtensionConfigs());
|
response.setExtensions(container.getExtensionConfigs());
|
||||||
return container.getHandler();
|
return container.getHandler();
|
||||||
});
|
});
|
||||||
this.factory.start();
|
factory.start();
|
||||||
}
|
}
|
||||||
catch (Throwable ex) {
|
catch (Throwable ex) {
|
||||||
throw new IllegalStateException("Unable to start Jetty WebSocketServerFactory", ex);
|
throw new IllegalStateException("Unable to start Jetty WebSocketServerFactory", ex);
|
||||||
|
@ -144,9 +148,10 @@ public class JettyRequestUpgradeStrategy implements RequestUpgradeStrategy, Serv
|
||||||
public void stop() {
|
public void stop() {
|
||||||
if (isRunning()) {
|
if (isRunning()) {
|
||||||
this.running = false;
|
this.running = false;
|
||||||
if (this.factory != null) {
|
WebSocketServerFactory factory = this.factory;
|
||||||
|
if (factory != null) {
|
||||||
try {
|
try {
|
||||||
this.factory.stop();
|
factory.stop();
|
||||||
}
|
}
|
||||||
catch (Throwable ex) {
|
catch (Throwable ex) {
|
||||||
throw new IllegalStateException("Unable to stop Jetty WebSocketServerFactory", ex);
|
throw new IllegalStateException("Unable to stop Jetty WebSocketServerFactory", ex);
|
||||||
|
@ -168,10 +173,12 @@ public class JettyRequestUpgradeStrategy implements RequestUpgradeStrategy, Serv
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<WebSocketExtension> getSupportedExtensions(ServerHttpRequest request) {
|
public List<WebSocketExtension> getSupportedExtensions(ServerHttpRequest request) {
|
||||||
if (this.supportedExtensions == null) {
|
List<WebSocketExtension> extensions = this.supportedExtensions;
|
||||||
this.supportedExtensions = buildWebSocketExtensions();
|
if (extensions == null) {
|
||||||
|
extensions = buildWebSocketExtensions();
|
||||||
|
this.supportedExtensions = extensions;
|
||||||
}
|
}
|
||||||
return this.supportedExtensions;
|
return extensions;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<WebSocketExtension> buildWebSocketExtensions() {
|
private List<WebSocketExtension> buildWebSocketExtensions() {
|
||||||
|
@ -185,8 +192,10 @@ public class JettyRequestUpgradeStrategy implements RequestUpgradeStrategy, Serv
|
||||||
|
|
||||||
@SuppressWarnings({"unchecked", "deprecation"})
|
@SuppressWarnings({"unchecked", "deprecation"})
|
||||||
private Set<String> getExtensionNames() {
|
private Set<String> getExtensionNames() {
|
||||||
|
WebSocketServerFactory factory = this.factory;
|
||||||
|
Assert.state(factory != null, "No WebSocketServerFactory available");
|
||||||
try {
|
try {
|
||||||
return this.factory.getAvailableExtensionNames();
|
return factory.getAvailableExtensionNames();
|
||||||
}
|
}
|
||||||
catch (IncompatibleClassChangeError ex) {
|
catch (IncompatibleClassChangeError ex) {
|
||||||
// Fallback for versions prior to 9.4.21:
|
// Fallback for versions prior to 9.4.21:
|
||||||
|
@ -194,7 +203,8 @@ public class JettyRequestUpgradeStrategy implements RequestUpgradeStrategy, Serv
|
||||||
// 9.4.21.v20190926: ExtensionFactory (interface -> abstract class) + deprecated
|
// 9.4.21.v20190926: ExtensionFactory (interface -> abstract class) + deprecated
|
||||||
Class<?> clazz = org.eclipse.jetty.websocket.api.extensions.ExtensionFactory.class;
|
Class<?> clazz = org.eclipse.jetty.websocket.api.extensions.ExtensionFactory.class;
|
||||||
Method method = ClassUtils.getMethod(clazz, "getExtensionNames");
|
Method method = ClassUtils.getMethod(clazz, "getExtensionNames");
|
||||||
return (Set<String>) ReflectionUtils.invokeMethod(method, this.factory.getExtensionFactory());
|
Set<String> result = (Set<String>) ReflectionUtils.invokeMethod(method, factory.getExtensionFactory());
|
||||||
|
return (result != null ? result : Collections.emptySet());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -209,7 +219,9 @@ public class JettyRequestUpgradeStrategy implements RequestUpgradeStrategy, Serv
|
||||||
Assert.isInstanceOf(ServletServerHttpResponse.class, response, "ServletServerHttpResponse required");
|
Assert.isInstanceOf(ServletServerHttpResponse.class, response, "ServletServerHttpResponse required");
|
||||||
HttpServletResponse servletResponse = ((ServletServerHttpResponse) response).getServletResponse();
|
HttpServletResponse servletResponse = ((ServletServerHttpResponse) response).getServletResponse();
|
||||||
|
|
||||||
Assert.isTrue(this.factory.isUpgradeRequest(servletRequest, servletResponse), "Not a WebSocket handshake");
|
WebSocketServerFactory factory = this.factory;
|
||||||
|
Assert.state(factory != null, "No WebSocketServerFactory available");
|
||||||
|
Assert.isTrue(factory.isUpgradeRequest(servletRequest, servletResponse), "Not a WebSocket handshake");
|
||||||
|
|
||||||
JettyWebSocketSession session = new JettyWebSocketSession(attributes, user);
|
JettyWebSocketSession session = new JettyWebSocketSession(attributes, user);
|
||||||
JettyWebSocketHandlerAdapter handlerAdapter = new JettyWebSocketHandlerAdapter(wsHandler, session);
|
JettyWebSocketHandlerAdapter handlerAdapter = new JettyWebSocketHandlerAdapter(wsHandler, session);
|
||||||
|
@ -219,7 +231,7 @@ public class JettyRequestUpgradeStrategy implements RequestUpgradeStrategy, Serv
|
||||||
|
|
||||||
try {
|
try {
|
||||||
containerHolder.set(container);
|
containerHolder.set(container);
|
||||||
this.factory.acceptWebSocket(servletRequest, servletResponse);
|
factory.acceptWebSocket(servletRequest, servletResponse);
|
||||||
}
|
}
|
||||||
catch (IOException ex) {
|
catch (IOException ex) {
|
||||||
throw new HandshakeFailureException(
|
throw new HandshakeFailureException(
|
||||||
|
@ -235,12 +247,13 @@ public class JettyRequestUpgradeStrategy implements RequestUpgradeStrategy, Serv
|
||||||
|
|
||||||
private final JettyWebSocketHandlerAdapter handler;
|
private final JettyWebSocketHandlerAdapter handler;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
private final String selectedProtocol;
|
private final String selectedProtocol;
|
||||||
|
|
||||||
private final List<ExtensionConfig> extensionConfigs;
|
private final List<ExtensionConfig> extensionConfigs;
|
||||||
|
|
||||||
public WebSocketHandlerContainer(
|
public WebSocketHandlerContainer(JettyWebSocketHandlerAdapter handler,
|
||||||
JettyWebSocketHandlerAdapter handler, String protocol, List<WebSocketExtension> extensions) {
|
@Nullable String protocol, List<WebSocketExtension> extensions) {
|
||||||
|
|
||||||
this.handler = handler;
|
this.handler = handler;
|
||||||
this.selectedProtocol = protocol;
|
this.selectedProtocol = protocol;
|
||||||
|
@ -259,6 +272,7 @@ public class JettyRequestUpgradeStrategy implements RequestUpgradeStrategy, Serv
|
||||||
return this.handler;
|
return this.handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
public String getSelectedProtocol() {
|
public String getSelectedProtocol() {
|
||||||
return this.selectedProtocol;
|
return this.selectedProtocol;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue