diff --git a/framework-docs/modules/ROOT/pages/web/websocket/server.adoc b/framework-docs/modules/ROOT/pages/web/websocket/server.adoc index 653f944dfc0..5fc4da352e6 100644 --- a/framework-docs/modules/ROOT/pages/web/websocket/server.adoc +++ b/framework-docs/modules/ROOT/pages/web/websocket/server.adoc @@ -280,9 +280,7 @@ The following example shows the XML configuration equivalent of the preceding ex NOTE: For client-side WebSocket configuration, you should use `WebSocketContainerFactoryBean` (XML) or `ContainerProvider.getWebSocketContainer()` (Java configuration). -For Jetty, you need to supply a pre-configured Jetty `WebSocketServerFactory` and plug -that into Spring's `DefaultHandshakeHandler` through your WebSocket Java config. -The following example shows how to do so: +For Jetty, you need to supply a `Consumer` callback to configure the WebSocket server. For example: [source,java,indent=0,subs="verbatim,quotes"] ---- @@ -292,62 +290,20 @@ The following example shows how to do so: @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { + + JettyRequestUpgradeStrategy upgradeStrategy = new JettyRequestUpgradeStrategy(); + upgradeStrategy.addWebSocketConfigurer(configurable -> { + policy.setInputBufferSize(8192); + policy.setIdleTimeout(600000); + }); + registry.addHandler(echoWebSocketHandler(), - "/echo").setHandshakeHandler(handshakeHandler()); - } - - @Bean - public DefaultHandshakeHandler handshakeHandler() { - - WebSocketPolicy policy = new WebSocketPolicy(WebSocketBehavior.SERVER); - policy.setInputBufferSize(8192); - policy.setIdleTimeout(600000); - - return new DefaultHandshakeHandler( - new JettyRequestUpgradeStrategy(new WebSocketServerFactory(policy))); + "/echo").setHandshakeHandler(new DefaultHandshakeHandler(upgradeStrategy)); } } ---- -The following example shows the XML configuration equivalent of the preceding example: - -[source,xml,indent=0,subs="verbatim,quotes,attributes"] ----- - - - - - - - - - - - - - - - - - - - - - - - - - - ----- 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 e29b696cccc..be68ffe5903 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-2022 the original author or authors. + * Copyright 2002-2023 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.Map; import java.util.function.Predicate; import java.util.stream.Collectors; +import jakarta.servlet.ServletContext; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import reactor.core.publisher.Mono; @@ -39,6 +40,7 @@ import org.springframework.util.Assert; import org.springframework.util.ClassUtils; import org.springframework.util.MultiValueMap; import org.springframework.util.StringUtils; +import org.springframework.web.context.ServletContextAware; import org.springframework.web.reactive.socket.HandshakeInfo; import org.springframework.web.reactive.socket.WebSocketHandler; import org.springframework.web.reactive.socket.server.RequestUpgradeStrategy; @@ -63,7 +65,7 @@ import org.springframework.web.server.ServerWebInputException; * @author Juergen Hoeller * @since 5.0 */ -public class HandshakeWebSocketService implements WebSocketService, Lifecycle { +public class HandshakeWebSocketService implements WebSocketService, ServletContextAware, Lifecycle { private static final String SEC_WEBSOCKET_KEY = "Sec-WebSocket-Key"; @@ -99,6 +101,7 @@ public class HandshakeWebSocketService implements WebSocketService, Lifecycle { private static final Log logger = LogFactory.getLog(HandshakeWebSocketService.class); + private final RequestUpgradeStrategy upgradeStrategy; @Nullable @@ -154,6 +157,13 @@ public class HandshakeWebSocketService implements WebSocketService, Lifecycle { return this.sessionAttributePredicate; } + @Override + public void setServletContext(ServletContext servletContext) { + if (getUpgradeStrategy() instanceof ServletContextAware servletContextAware) { + servletContextAware.setServletContext(servletContext); + } + } + @Override public void start() { diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/socket/server/support/WebSocketHandlerAdapter.java b/spring-webflux/src/main/java/org/springframework/web/reactive/socket/server/support/WebSocketHandlerAdapter.java index ef8c697038e..b79bbd0f476 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/socket/server/support/WebSocketHandlerAdapter.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/socket/server/support/WebSocketHandlerAdapter.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2022 the original author or authors. + * Copyright 2002-2023 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. @@ -16,11 +16,13 @@ package org.springframework.web.reactive.socket.server.support; +import jakarta.servlet.ServletContext; import reactor.core.publisher.Mono; import org.springframework.context.annotation.ImportRuntimeHints; import org.springframework.core.Ordered; import org.springframework.util.Assert; +import org.springframework.web.context.ServletContextAware; import org.springframework.web.reactive.HandlerAdapter; import org.springframework.web.reactive.HandlerResult; import org.springframework.web.reactive.socket.WebSocketHandler; @@ -47,7 +49,7 @@ import org.springframework.web.server.ServerWebExchange; * @since 5.0 */ @ImportRuntimeHints(HandshakeWebSocketServiceRuntimeHints.class) -public class WebSocketHandlerAdapter implements HandlerAdapter, Ordered { +public class WebSocketHandlerAdapter implements HandlerAdapter, ServletContextAware, Ordered { private final WebSocketService webSocketService; @@ -97,6 +99,13 @@ public class WebSocketHandlerAdapter implements HandlerAdapter, Ordered { return this.webSocketService; } + @Override + public void setServletContext(ServletContext servletContext) { + if (this.webSocketService instanceof ServletContextAware servletContextAware) { + servletContextAware.setServletContext(servletContext); + } + } + @Override public boolean supports(Object handler) { diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/socket/server/upgrade/JettyRequestUpgradeStrategy.java b/spring-webflux/src/main/java/org/springframework/web/reactive/socket/server/upgrade/JettyRequestUpgradeStrategy.java index dbb14bc52c6..94a1db672b3 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/socket/server/upgrade/JettyRequestUpgradeStrategy.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/socket/server/upgrade/JettyRequestUpgradeStrategy.java @@ -16,6 +16,7 @@ package org.springframework.web.reactive.socket.server.upgrade; +import java.util.function.Consumer; import java.util.function.Supplier; import jakarta.servlet.ServletContext; @@ -23,6 +24,7 @@ import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.eclipse.jetty.ee10.websocket.server.JettyWebSocketCreator; import org.eclipse.jetty.ee10.websocket.server.JettyWebSocketServerContainer; +import org.eclipse.jetty.websocket.api.Configurable; import reactor.core.publisher.Mono; import org.springframework.core.io.buffer.DataBufferFactory; @@ -31,6 +33,7 @@ import org.springframework.http.server.reactive.ServerHttpRequestDecorator; import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.http.server.reactive.ServerHttpResponseDecorator; import org.springframework.lang.Nullable; +import org.springframework.web.context.ServletContextAware; import org.springframework.web.reactive.socket.HandshakeInfo; import org.springframework.web.reactive.socket.WebSocketHandler; import org.springframework.web.reactive.socket.adapter.ContextWebSocketHandler; @@ -45,7 +48,30 @@ import org.springframework.web.server.ServerWebExchange; * @author Rossen Stoyanchev * @since 5.3.4 */ -public class JettyRequestUpgradeStrategy implements RequestUpgradeStrategy { +public class JettyRequestUpgradeStrategy implements RequestUpgradeStrategy, ServletContextAware { + + @Nullable + private Consumer webSocketConfigurer; + + + /** + * Add a callback to configure WebSocket server parameters on + * {@link JettyWebSocketServerContainer}. + * @since 6.1.0 + */ + public void addWebSocketConfigurer(Consumer webSocketConfigurer) { + this.webSocketConfigurer = (this.webSocketConfigurer != null ? + this.webSocketConfigurer.andThen(webSocketConfigurer) : webSocketConfigurer); + } + + @Override + public void setServletContext(ServletContext servletContext) { + JettyWebSocketServerContainer container = JettyWebSocketServerContainer.getContainer(servletContext); + if (container != null && this.webSocketConfigurer != null) { + this.webSocketConfigurer.accept(container); + } + } + @Override public Mono upgrade( diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/server/jetty/JettyRequestUpgradeStrategy.java b/spring-websocket/src/main/java/org/springframework/web/socket/server/jetty/JettyRequestUpgradeStrategy.java index 7bd6c9f7f03..8ca477dd6c9 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/server/jetty/JettyRequestUpgradeStrategy.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/server/jetty/JettyRequestUpgradeStrategy.java @@ -21,12 +21,14 @@ import java.security.Principal; import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.function.Consumer; import jakarta.servlet.ServletContext; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import org.eclipse.jetty.ee10.websocket.server.JettyWebSocketCreator; import org.eclipse.jetty.ee10.websocket.server.JettyWebSocketServerContainer; +import org.eclipse.jetty.websocket.api.Configurable; import org.springframework.http.server.ServerHttpRequest; import org.springframework.http.server.ServerHttpResponse; @@ -34,6 +36,7 @@ import org.springframework.http.server.ServletServerHttpRequest; import org.springframework.http.server.ServletServerHttpResponse; import org.springframework.lang.Nullable; import org.springframework.util.Assert; +import org.springframework.web.context.ServletContextAware; import org.springframework.web.socket.WebSocketExtension; import org.springframework.web.socket.WebSocketHandler; import org.springframework.web.socket.adapter.jetty.JettyWebSocketHandlerAdapter; @@ -47,11 +50,15 @@ import org.springframework.web.socket.server.RequestUpgradeStrategy; * @author Rossen Stoyanchev * @since 5.3.4 */ -public class JettyRequestUpgradeStrategy implements RequestUpgradeStrategy { +public class JettyRequestUpgradeStrategy implements RequestUpgradeStrategy, ServletContextAware { private static final String[] SUPPORTED_VERSIONS = new String[] {"13"}; + @Nullable + private Consumer webSocketConfigurer; + + @Override public String[] getSupportedVersions() { return SUPPORTED_VERSIONS; @@ -62,6 +69,24 @@ public class JettyRequestUpgradeStrategy implements RequestUpgradeStrategy { return Collections.emptyList(); } + /** + * Add a callback to configure WebSocket server parameters on + * {@link JettyWebSocketServerContainer}. + * @since 6.1.0 + */ + public void addWebSocketConfigurer(Consumer webSocketConfigurer) { + this.webSocketConfigurer = (this.webSocketConfigurer != null ? + this.webSocketConfigurer.andThen(webSocketConfigurer) : webSocketConfigurer); + } + + @Override + public void setServletContext(ServletContext servletContext) { + JettyWebSocketServerContainer container = JettyWebSocketServerContainer.getContainer(servletContext); + if (container != null && this.webSocketConfigurer != null) { + this.webSocketConfigurer.accept(container); + } + } + @Override public void upgrade(ServerHttpRequest request, ServerHttpResponse response,