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] 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..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. @@ -50,19 +50,38 @@ public class ServerResponseResultHandler implements HandlerResultHandler, Initia /** * 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 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) {
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 b81b789c51..ce18760caf 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-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.
@@ -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;
@@ -65,6 +66,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";
@@ -194,9 +198,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 9d2f8f20e8..237be64cf5 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;
@@ -67,6 +68,10 @@ import org.springframework.web.socket.server.standard.StandardWebSocketUpgradeSt
*/
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");
+
+
protected final Log logger = LogFactory.getLog(getClass());
private final RequestUpgradeStrategy requestUpgradeStrategy;
@@ -169,11 +174,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;
}
@@ -255,7 +261,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));