Skip to content

Commit fd1ca46

Browse files
committed
Thread-safe access to WebSocketServerFactory and WebSocketExtensions
See gh-24745
1 parent b7b3689 commit fd1ca46

File tree

1 file changed

+31
-17
lines changed

1 file changed

+31
-17
lines changed

spring-websocket/src/main/java/org/springframework/web/socket/server/jetty/JettyRequestUpgradeStrategy.java

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2019 the original author or authors.
2+
* Copyright 2002-2020 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -20,6 +20,7 @@
2020
import java.lang.reflect.Method;
2121
import java.security.Principal;
2222
import java.util.ArrayList;
23+
import java.util.Collections;
2324
import java.util.List;
2425
import java.util.Map;
2526
import java.util.Set;
@@ -72,7 +73,7 @@ public class JettyRequestUpgradeStrategy implements RequestUpgradeStrategy, Serv
7273
private WebSocketPolicy policy;
7374

7475
@Nullable
75-
private WebSocketServerFactory factory;
76+
private volatile WebSocketServerFactory factory;
7677

7778
@Nullable
7879
private ServletContext servletContext;
@@ -122,17 +123,20 @@ public void start() {
122123
if (!isRunning()) {
123124
this.running = true;
124125
try {
125-
if (this.factory == null) {
126-
this.factory = new WebSocketServerFactory(this.servletContext, this.policy);
126+
WebSocketServerFactory factory = this.factory;
127+
if (factory == null) {
128+
Assert.state(this.servletContext != null, "No ServletContext set");
129+
factory = new WebSocketServerFactory(this.servletContext, this.policy);
130+
this.factory = factory;
127131
}
128-
this.factory.setCreator((request, response) -> {
132+
factory.setCreator((request, response) -> {
129133
WebSocketHandlerContainer container = containerHolder.get();
130134
Assert.state(container != null, "Expected WebSocketHandlerContainer");
131135
response.setAcceptedSubProtocol(container.getSelectedProtocol());
132136
response.setExtensions(container.getExtensionConfigs());
133137
return container.getHandler();
134138
});
135-
this.factory.start();
139+
factory.start();
136140
}
137141
catch (Throwable ex) {
138142
throw new IllegalStateException("Unable to start Jetty WebSocketServerFactory", ex);
@@ -144,9 +148,10 @@ public void start() {
144148
public void stop() {
145149
if (isRunning()) {
146150
this.running = false;
147-
if (this.factory != null) {
151+
WebSocketServerFactory factory = this.factory;
152+
if (factory != null) {
148153
try {
149-
this.factory.stop();
154+
factory.stop();
150155
}
151156
catch (Throwable ex) {
152157
throw new IllegalStateException("Unable to stop Jetty WebSocketServerFactory", ex);
@@ -168,10 +173,12 @@ public String[] getSupportedVersions() {
168173

169174
@Override
170175
public List<WebSocketExtension> getSupportedExtensions(ServerHttpRequest request) {
171-
if (this.supportedExtensions == null) {
172-
this.supportedExtensions = buildWebSocketExtensions();
176+
List<WebSocketExtension> extensions = this.supportedExtensions;
177+
if (extensions == null) {
178+
extensions = buildWebSocketExtensions();
179+
this.supportedExtensions = extensions;
173180
}
174-
return this.supportedExtensions;
181+
return extensions;
175182
}
176183

177184
private List<WebSocketExtension> buildWebSocketExtensions() {
@@ -185,16 +192,19 @@ private List<WebSocketExtension> buildWebSocketExtensions() {
185192

186193
@SuppressWarnings({"unchecked", "deprecation"})
187194
private Set<String> getExtensionNames() {
195+
WebSocketServerFactory factory = this.factory;
196+
Assert.state(factory != null, "No WebSocketServerFactory available");
188197
try {
189-
return this.factory.getAvailableExtensionNames();
198+
return factory.getAvailableExtensionNames();
190199
}
191200
catch (IncompatibleClassChangeError ex) {
192201
// Fallback for versions prior to 9.4.21:
193202
// 9.4.20.v20190813: ExtensionFactory (abstract class -> interface)
194203
// 9.4.21.v20190926: ExtensionFactory (interface -> abstract class) + deprecated
195204
Class<?> clazz = org.eclipse.jetty.websocket.api.extensions.ExtensionFactory.class;
196205
Method method = ClassUtils.getMethod(clazz, "getExtensionNames");
197-
return (Set<String>) ReflectionUtils.invokeMethod(method, this.factory.getExtensionFactory());
206+
Set<String> result = (Set<String>) ReflectionUtils.invokeMethod(method, factory.getExtensionFactory());
207+
return (result != null ? result : Collections.emptySet());
198208
}
199209
}
200210

@@ -209,7 +219,9 @@ public void upgrade(ServerHttpRequest request, ServerHttpResponse response,
209219
Assert.isInstanceOf(ServletServerHttpResponse.class, response, "ServletServerHttpResponse required");
210220
HttpServletResponse servletResponse = ((ServletServerHttpResponse) response).getServletResponse();
211221

212-
Assert.isTrue(this.factory.isUpgradeRequest(servletRequest, servletResponse), "Not a WebSocket handshake");
222+
WebSocketServerFactory factory = this.factory;
223+
Assert.state(factory != null, "No WebSocketServerFactory available");
224+
Assert.isTrue(factory.isUpgradeRequest(servletRequest, servletResponse), "Not a WebSocket handshake");
213225

214226
JettyWebSocketSession session = new JettyWebSocketSession(attributes, user);
215227
JettyWebSocketHandlerAdapter handlerAdapter = new JettyWebSocketHandlerAdapter(wsHandler, session);
@@ -219,7 +231,7 @@ public void upgrade(ServerHttpRequest request, ServerHttpResponse response,
219231

220232
try {
221233
containerHolder.set(container);
222-
this.factory.acceptWebSocket(servletRequest, servletResponse);
234+
factory.acceptWebSocket(servletRequest, servletResponse);
223235
}
224236
catch (IOException ex) {
225237
throw new HandshakeFailureException(
@@ -235,12 +247,13 @@ private static class WebSocketHandlerContainer {
235247

236248
private final JettyWebSocketHandlerAdapter handler;
237249

250+
@Nullable
238251
private final String selectedProtocol;
239252

240253
private final List<ExtensionConfig> extensionConfigs;
241254

242-
public WebSocketHandlerContainer(
243-
JettyWebSocketHandlerAdapter handler, String protocol, List<WebSocketExtension> extensions) {
255+
public WebSocketHandlerContainer(JettyWebSocketHandlerAdapter handler,
256+
@Nullable String protocol, List<WebSocketExtension> extensions) {
244257

245258
this.handler = handler;
246259
this.selectedProtocol = protocol;
@@ -259,6 +272,7 @@ public JettyWebSocketHandlerAdapter getHandler() {
259272
return this.handler;
260273
}
261274

275+
@Nullable
262276
public String getSelectedProtocol() {
263277
return this.selectedProtocol;
264278
}

0 commit comments

Comments
 (0)