From 7536777a18f6fa7141d2e8b6be06992812ea3d4c Mon Sep 17 00:00:00 2001 From: Daeho Kwon Date: Sat, 25 Jan 2025 04:21:10 +0900 Subject: [PATCH 1/5] Replace hardcoded "Sec-WebSocket-Version" with constant Closes gh-34319 Signed-off-by: Daeho Kwon --- .../web/socket/server/support/AbstractHandshakeHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/server/support/AbstractHandshakeHandler.java b/spring-websocket/src/main/java/org/springframework/web/socket/server/support/AbstractHandshakeHandler.java index 6c05cfda70..a32692c8af 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/server/support/AbstractHandshakeHandler.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/server/support/AbstractHandshakeHandler.java @@ -296,7 +296,7 @@ public abstract class AbstractHandshakeHandler implements HandshakeHandler, Life protected void handleWebSocketVersionNotSupported(ServerHttpRequest request, ServerHttpResponse response) { if (logger.isErrorEnabled()) { - String version = request.getHeaders().getFirst("Sec-WebSocket-Version"); + String version = request.getHeaders().getFirst(WebSocketHttpHeaders.SEC_WEBSOCKET_VERSION); logger.error(LogFormatUtils.formatValue( "Handshake failed due to unsupported WebSocket version: " + version + ". Supported versions: " + Arrays.toString(getSupportedVersions()), -1, true)); From a9ecf9052417ac570921f917bf7d416d907b44cf Mon Sep 17 00:00:00 2001 From: Pierre Rossato Date: Sat, 1 Feb 2025 17:38:09 +0100 Subject: [PATCH 2/5] Minor update in WebSocket STOMP documentation Closes gh-34353 Signed-off-by: Pierre Rossato --- .../ROOT/pages/web/websocket/stomp/ordered-messages.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework-docs/modules/ROOT/pages/web/websocket/stomp/ordered-messages.adoc b/framework-docs/modules/ROOT/pages/web/websocket/stomp/ordered-messages.adoc index a5d5f82f3a..d56552286f 100644 --- a/framework-docs/modules/ROOT/pages/web/websocket/stomp/ordered-messages.adoc +++ b/framework-docs/modules/ROOT/pages/web/websocket/stomp/ordered-messages.adoc @@ -19,6 +19,6 @@ from where they are handled according to their destination prefix. As the channe a `ThreadPoolExecutor`, messages are processed in different threads, and the resulting sequence of handling may not match the exact order in which they were received. -To enable ordered publishing, set the `setPreserveReceiveOrder` flag as follows: +To enable ordered receiving, set the `setPreserveReceiveOrder` flag as follows: include-code::./ReceiveOrderWebSocketConfiguration[tag=snippet,indent=0] From 8b07f93620d1710cf3f4323675202f41b77eb513 Mon Sep 17 00:00:00 2001 From: Tarek Mues Date: Wed, 11 Dec 2024 03:10:05 +0100 Subject: [PATCH 3/5] Add getters ServerResponseResultHandler See gh-34066 --- .../support/ServerResponseResultHandler.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/support/ServerResponseResultHandler.java b/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/support/ServerResponseResultHandler.java index 1eac334d3f..5ee09dd637 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/support/ServerResponseResultHandler.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/support/ServerResponseResultHandler.java @@ -47,6 +47,12 @@ public class ServerResponseResultHandler implements HandlerResultHandler, Initia private int order = 0; + /** + * Return the configured {@link HttpMessageWriter}'s. + */ + public List> getMessageWriters() { + return this.messageWriters; + } /** * Configure HTTP message writers to serialize the request body with. @@ -56,6 +62,16 @@ public class ServerResponseResultHandler implements HandlerResultHandler, Initia this.messageWriters = configurer; } + /** + * Return the configured {@link ViewResolver}'s. + */ + public List getViewResolvers() { + return this.viewResolvers; + } + + /** + * Set the current view resolvers. + */ public void setViewResolvers(List viewResolvers) { this.viewResolvers = viewResolvers; } From 1cea1fe962cc95544fce7be8fd2f56419e89aaaf Mon Sep 17 00:00:00 2001 From: rstoyanchev Date: Mon, 3 Feb 2025 15:15:21 +0000 Subject: [PATCH 4/5] Polishing contribution Closes gh-34066 --- .../support/ServerResponseResultHandler.java | 27 ++++++++++--------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/support/ServerResponseResultHandler.java b/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/support/ServerResponseResultHandler.java index 5ee09dd637..7161de6133 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/support/ServerResponseResultHandler.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/function/server/support/ServerResponseResultHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -47,26 +47,21 @@ public class ServerResponseResultHandler implements HandlerResultHandler, Initia private int order = 0; - /** - * Return the configured {@link HttpMessageWriter}'s. - */ - public List> getMessageWriters() { - return this.messageWriters; - } /** * Configure HTTP message writers to serialize the request body with. - *

By default this is set to {@link ServerCodecConfigurer}'s default writers. + *

By default, this is set to {@link ServerCodecConfigurer}'s default writers. */ public void setMessageWriters(List> configurer) { this.messageWriters = configurer; } /** - * Return the configured {@link ViewResolver}'s. + * Return the configured {@link HttpMessageWriter}'s. + * @since 6.2.3 */ - public List getViewResolvers() { - return this.viewResolvers; + public List> getMessageWriters() { + return this.messageWriters; } /** @@ -76,9 +71,17 @@ public class ServerResponseResultHandler implements HandlerResultHandler, Initia this.viewResolvers = viewResolvers; } + /** + * Return the configured {@link ViewResolver}'s. + * @since 6.2.3 + */ + public List getViewResolvers() { + return this.viewResolvers; + } + /** * Set the order for this result handler relative to others. - *

By default set to 0. It is generally safe to place it early in the + *

By default, set to 0. It is generally safe to place it early in the * order as it looks for a concrete return type. */ public void setOrder(int order) { From f477c1653d2d8198bede242f4ea4d4a599727bcc Mon Sep 17 00:00:00 2001 From: rstoyanchev Date: Mon, 3 Feb 2025 15:28:27 +0000 Subject: [PATCH 5/5] Allow WebSocket over HTTP CONNECT Closes gh-34044 --- .../server/support/HandshakeWebSocketService.java | 10 +++++++--- .../server/support/AbstractHandshakeHandler.java | 13 +++++++++---- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/socket/server/support/HandshakeWebSocketService.java b/spring-webflux/src/main/java/org/springframework/web/reactive/socket/server/support/HandshakeWebSocketService.java index 603d8e6183..c54f38d9bc 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/socket/server/support/HandshakeWebSocketService.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/socket/server/support/HandshakeWebSocketService.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,6 +22,7 @@ import java.security.Principal; import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.function.Predicate; import java.util.stream.Collectors; @@ -66,6 +67,9 @@ import org.springframework.web.server.ServerWebInputException; */ public class HandshakeWebSocketService implements WebSocketService, Lifecycle { + // For WebSocket upgrades in HTTP/2 (see RFC 8441) + private static final HttpMethod CONNECT_METHOD = HttpMethod.valueOf("CONNECT"); + private static final String SEC_WEBSOCKET_KEY = "Sec-WebSocket-Key"; private static final String SEC_WEBSOCKET_PROTOCOL = "Sec-WebSocket-Protocol"; @@ -201,9 +205,9 @@ public class HandshakeWebSocketService implements WebSocketService, Lifecycle { HttpMethod method = request.getMethod(); HttpHeaders headers = request.getHeaders(); - if (HttpMethod.GET != method) { + if (HttpMethod.GET != method && CONNECT_METHOD != method) { return Mono.error(new MethodNotAllowedException( - request.getMethod(), Collections.singleton(HttpMethod.GET))); + request.getMethod(), Set.of(HttpMethod.GET, CONNECT_METHOD))); } if (!"WebSocket".equalsIgnoreCase(headers.getUpgrade())) { diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/server/support/AbstractHandshakeHandler.java b/spring-websocket/src/main/java/org/springframework/web/socket/server/support/AbstractHandshakeHandler.java index a32692c8af..acde43c3cc 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/server/support/AbstractHandshakeHandler.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/server/support/AbstractHandshakeHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,6 +25,7 @@ import java.util.Collections; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -77,6 +78,9 @@ import org.springframework.web.socket.server.standard.WebSphereRequestUpgradeStr */ public abstract class AbstractHandshakeHandler implements HandshakeHandler, Lifecycle { + // For WebSocket upgrades in HTTP/2 (see RFC 8441) + private static final HttpMethod CONNECT_METHOD = HttpMethod.valueOf("CONNECT"); + private static final boolean tomcatWsPresent; private static final boolean jettyWsPresent; @@ -210,11 +214,12 @@ public abstract class AbstractHandshakeHandler implements HandshakeHandler, Life logger.trace("Processing request " + request.getURI() + " with headers=" + headers); } try { - if (HttpMethod.GET != request.getMethod()) { + HttpMethod httpMethod = request.getMethod(); + if (HttpMethod.GET != httpMethod && CONNECT_METHOD != httpMethod) { response.setStatusCode(HttpStatus.METHOD_NOT_ALLOWED); - response.getHeaders().setAllow(Collections.singleton(HttpMethod.GET)); + response.getHeaders().setAllow(Set.of(HttpMethod.GET, CONNECT_METHOD)); if (logger.isErrorEnabled()) { - logger.error("Handshake failed due to unexpected HTTP method: " + request.getMethod()); + logger.error("Handshake failed due to unexpected HTTP method: " + httpMethod); } return false; }