Merge branch '3.1.x'

Closes gh-37664
pull/37640/head
Andy Wilkinson 1 year ago
commit 12108e58e9

@ -16,9 +16,10 @@
package org.springframework.boot.autoconfigure.websocket.servlet; package org.springframework.boot.autoconfigure.websocket.servlet;
import java.util.List; import java.util.EnumSet;
import jakarta.servlet.DispatcherType; import jakarta.servlet.DispatcherType;
import jakarta.servlet.FilterRegistration.Dynamic;
import jakarta.servlet.Servlet; import jakarta.servlet.Servlet;
import jakarta.websocket.server.ServerContainer; import jakarta.websocket.server.ServerContainer;
import org.apache.catalina.startup.Tomcat; import org.apache.catalina.startup.Tomcat;
@ -29,13 +30,15 @@ import org.eclipse.jetty.ee10.websocket.servlet.WebSocketUpgradeFilter;
import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnNotWarDeployment;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration; import org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryAutoConfiguration;
import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.boot.web.servlet.ServletContextInitializer;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered; import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
/** /**
* Auto configuration for WebSocket servlet server in embedded Tomcat, Jetty or Undertow. * Auto configuration for WebSocket servlet server in embedded Tomcat, Jetty or Undertow.
@ -86,17 +89,16 @@ public class WebSocketServletAutoConfiguration {
} }
@Bean @Bean
@ConditionalOnMissingBean(value = WebSocketUpgradeFilter.class, @ConditionalOnNotWarDeployment
parameterizedContainer = FilterRegistrationBean.class) @Order(Ordered.LOWEST_PRECEDENCE)
FilterRegistrationBean<WebSocketUpgradeFilter> webSocketUpgradeFilter() { @ConditionalOnMissingBean(name = "websocketUpgradeFilterServletContextInitializer")
WebSocketUpgradeFilter websocketFilter = new WebSocketUpgradeFilter(); ServletContextInitializer websocketUpgradeFilterServletContextInitializer() {
FilterRegistrationBean<WebSocketUpgradeFilter> registration = new FilterRegistrationBean<>(websocketFilter); return (servletContext) -> {
Dynamic registration = servletContext.addFilter(WebSocketUpgradeFilter.class.getName(),
new WebSocketUpgradeFilter());
registration.setAsyncSupported(true); registration.setAsyncSupported(true);
registration.setDispatcherTypes(DispatcherType.REQUEST); registration.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), false, "/*");
registration.setName(WebSocketUpgradeFilter.class.getName()); };
registration.setOrder(Ordered.LOWEST_PRECEDENCE);
registration.setUrlPatterns(List.of("/*"));
return registration;
} }
} }

@ -36,6 +36,7 @@ import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.MethodSource;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration; import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner; import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
@ -46,7 +47,9 @@ import org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory; import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.WebServer; import org.springframework.boot.web.server.WebServer;
import org.springframework.boot.web.server.WebServerFactoryCustomizerBeanPostProcessor; import org.springframework.boot.web.server.WebServerFactoryCustomizerBeanPostProcessor;
import org.springframework.boot.web.servlet.AbstractFilterRegistrationBean;
import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletContextInitializer;
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext; import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;
import org.springframework.boot.web.servlet.server.ServletWebServerFactory; import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
@ -103,34 +106,42 @@ class WebSocketServletAutoConfigurationTests {
} }
@Test @Test
@SuppressWarnings("rawtypes") void jettyWebSocketUpgradeFilterIsAddedToServletContext() {
void whenCustomUpgradeFilterRegistrationIsDefinedAutoConfiguredRegistrationOfJettyUpgradeFilterBacksOff() { try (AnnotationConfigServletWebServerApplicationContext context = new AnnotationConfigServletWebServerApplicationContext(
new WebApplicationContextRunner() JettyConfiguration.class, WebSocketServletAutoConfiguration.JettyWebSocketConfiguration.class)) {
.withConfiguration(AutoConfigurations.of(JettyConfiguration.class, assertThat(context.getServletContext().getFilterRegistration(WebSocketUpgradeFilter.class.getName()))
WebSocketServletAutoConfiguration.JettyWebSocketConfiguration.class)) .isNotNull();
.withUserConfiguration(CustomUpgradeFilterRegistrationConfiguration.class) }
.run((context) -> {
Map<String, FilterRegistrationBean> filterRegistrations = context
.getBeansOfType(FilterRegistrationBean.class);
assertThat(filterRegistrations).containsOnlyKeys("unauthorizedFilter",
"customUpgradeFilterRegistration");
});
} }
@Test @Test
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
void whenCustomUpgradeFilterIsDefinedAutoConfiguredRegistrationOfJettyUpgradeFilterBacksOff() { void jettyWebSocketUpgradeFilterIsNotExposedAsABean() {
new WebApplicationContextRunner() new WebApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(JettyConfiguration.class, .withConfiguration(AutoConfigurations.of(JettyConfiguration.class,
WebSocketServletAutoConfiguration.JettyWebSocketConfiguration.class)) WebSocketServletAutoConfiguration.JettyWebSocketConfiguration.class))
.withUserConfiguration(CustomUpgradeFilterConfiguration.class)
.run((context) -> { .run((context) -> {
Map<String, FilterRegistrationBean> filterRegistrations = context Map<String, Filter> filters = context.getBeansOfType(Filter.class);
.getBeansOfType(FilterRegistrationBean.class); assertThat(filters.values()).noneMatch(WebSocketUpgradeFilter.class::isInstance);
assertThat(filterRegistrations).containsOnlyKeys("unauthorizedFilter"); Map<String, AbstractFilterRegistrationBean> filterRegistrations = context
.getBeansOfType(AbstractFilterRegistrationBean.class);
assertThat(filterRegistrations.values()).extracting(AbstractFilterRegistrationBean::getFilter)
.noneMatch(WebSocketUpgradeFilter.class::isInstance);
}); });
} }
@Test
void jettyWebSocketUpgradeFilterServletContextInitializerBacksOffWhenBeanWithSameNameIsDefined() {
try (AnnotationConfigServletWebServerApplicationContext context = new AnnotationConfigServletWebServerApplicationContext(
JettyConfiguration.class, CustomWebSocketUpgradeFilterServletContextInitializerConfiguration.class,
WebSocketServletAutoConfiguration.JettyWebSocketConfiguration.class)) {
BeanDefinition definition = context.getBeanFactory()
.getBeanDefinition("websocketUpgradeFilterServletContextInitializer");
assertThat(definition.getFactoryBeanName())
.contains("CustomWebSocketUpgradeFilterServletContextInitializerConfiguration");
}
}
static Stream<Arguments> testConfiguration() { static Stream<Arguments> testConfiguration() {
String response = "Tomcat"; String response = "Tomcat";
return Stream.of( return Stream.of(
@ -194,23 +205,13 @@ class WebSocketServletAutoConfigurationTests {
} }
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
static class CustomUpgradeFilterRegistrationConfiguration { static class CustomWebSocketUpgradeFilterServletContextInitializerConfiguration {
@Bean @Bean
FilterRegistrationBean<WebSocketUpgradeFilter> customUpgradeFilterRegistration() { ServletContextInitializer websocketUpgradeFilterServletContextInitializer() {
FilterRegistrationBean<WebSocketUpgradeFilter> registration = new FilterRegistrationBean<>( return (servletContext) -> {
new WebSocketUpgradeFilter());
return registration;
}
} };
@Configuration(proxyBeanMethods = false)
static class CustomUpgradeFilterConfiguration {
@Bean
WebSocketUpgradeFilter customUpgradeFilter() {
return new WebSocketUpgradeFilter();
} }
} }

Loading…
Cancel
Save