mirror of
https://github.com/spring-projects/spring-framework.git
synced 2026-09-17 16:30:28 +00:00
Copy WS handshake headers to store in session
Prior to this commit, the `StandardWebSocketUpgradeStrategy` would get the HTTP headers from the handshake request and store them in the WebSocket session for the entire duration of the session. As of gh-36334, Spring MVC manages HTTP directly with a native API instead of copying them. This improves performance but also uncovered this bug: we cannot keep a reference to HTTP headers once the HTTP exchange is finished, because such resources can be recycled and reused. This commit ensures that the handshake headers are copied into the session info to keep them around for the entire duration of the session. Without that, Tomcat will raise an `IllegalStateException` at runtime. This was already done for WebFlux in SPR-17250, but the latest header management changes in Framework uncovered this issue for the Standard WebSocket container case. Fixes gh-36486
This commit is contained in:
+3
-1
@@ -97,7 +97,9 @@ public class StandardWebSocketUpgradeStrategy implements RequestUpgradeStrategy
|
||||
@Nullable Principal user, WebSocketHandler wsHandler, Map<String, Object> attrs)
|
||||
throws HandshakeFailureException {
|
||||
|
||||
HttpHeaders headers = request.getHeaders();
|
||||
// Copy request headers, as they might be pooled and recycled by
|
||||
// the server implementation once the handshake HTTP exchange is done.
|
||||
HttpHeaders headers = HttpHeaders.copyOf(request.getHeaders());
|
||||
InetSocketAddress localAddr = null;
|
||||
try {
|
||||
localAddr = request.getLocalAddress();
|
||||
|
||||
+25
-1
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.web.socket;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -87,6 +88,26 @@ class WebSocketHandshakeTests extends AbstractWebSocketIntegrationTests {
|
||||
}
|
||||
|
||||
|
||||
@ParameterizedWebSocketTest
|
||||
void useHeadersAfterHandshake(
|
||||
WebSocketTestServer server, WebSocketClient webSocketClient, TestInfo testInfo) throws Exception {
|
||||
|
||||
super.setup(server, webSocketClient, testInfo);
|
||||
|
||||
WebSocketHttpHeaders headers = new WebSocketHttpHeaders();
|
||||
URI url = URI.create(getWsBaseUrl() + "/ws");
|
||||
WebSocketSession session = this.webSocketClient.execute(new TextWebSocketHandler(), headers, url).get();
|
||||
TestWebSocketHandler serverHandler = this.wac.getBean(TestWebSocketHandler.class);
|
||||
serverHandler.setWaitMessageCount(1);
|
||||
|
||||
session.sendMessage(new TextMessage("header"));
|
||||
|
||||
session.close();
|
||||
serverHandler.await();
|
||||
assertThat(serverHandler.getReceivedMessages()).hasSize(1);
|
||||
}
|
||||
|
||||
|
||||
@Configuration
|
||||
@EnableWebSocket
|
||||
static class TestConfig implements WebSocketConfigurer {
|
||||
@@ -131,7 +152,10 @@ class WebSocketHandshakeTests extends AbstractWebSocketIntegrationTests {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) {
|
||||
public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws IOException {
|
||||
if (message instanceof TextMessage textMessage && textMessage.getPayload().equals("header")) {
|
||||
session.sendMessage(new TextMessage(session.getHandshakeHeaders().headerNames().toString()));
|
||||
}
|
||||
this.receivedMessages.add(message);
|
||||
if (this.receivedMessages.size() >= this.waitMessageCount) {
|
||||
this.latch.countDown();
|
||||
|
||||
Reference in New Issue
Block a user