diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/handler/AbstractHandlerMapping.java b/spring-webflux/src/main/java/org/springframework/web/reactive/handler/AbstractHandlerMapping.java index e54dce96fe3..80db15d5ad1 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/handler/AbstractHandlerMapping.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/handler/AbstractHandlerMapping.java @@ -218,20 +218,17 @@ public abstract class AbstractHandlerMapping extends ApplicationObjectSupport } private ApiVersionHolder initApiVersion(ServerWebExchange exchange) { - ApiVersionHolder versionHolder = exchange.getAttribute(API_VERSION_ATTRIBUTE); - if (versionHolder == null) { - if (this.apiVersionStrategy == null) { - versionHolder = ApiVersionHolder.EMPTY; + ApiVersionHolder versionHolder; + if (this.apiVersionStrategy == null) { + versionHolder = ApiVersionHolder.EMPTY; + } + else { + try { + Comparable version = this.apiVersionStrategy.resolveParseAndValidateVersion(exchange); + versionHolder = ApiVersionHolder.fromVersion(version); } - else { - Comparable version; - try { - version = this.apiVersionStrategy.resolveParseAndValidateVersion(exchange); - versionHolder = ApiVersionHolder.fromVersion(version); - } - catch (RuntimeException ex) { - versionHolder = ApiVersionHolder.fromError(ex); - } + catch (RuntimeException ex) { + versionHolder = ApiVersionHolder.fromError(ex); } } exchange.getAttributes().put(API_VERSION_ATTRIBUTE, versionHolder); diff --git a/spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestMappingVersionIntegrationTests.java b/spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestMappingVersionIntegrationTests.java index 7457a8d1d8f..ef5973388ee 100644 --- a/spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestMappingVersionIntegrationTests.java +++ b/spring-webflux/src/test/java/org/springframework/web/reactive/result/method/annotation/RequestMappingVersionIntegrationTests.java @@ -18,6 +18,8 @@ package org.springframework.web.reactive.result.method.annotation; import java.net.URI; +import org.junit.jupiter.api.Test; + import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.http.RequestEntity; @@ -29,8 +31,10 @@ import org.springframework.web.client.HttpClientErrorException; import org.springframework.web.reactive.accept.StandardApiVersionDeprecationHandler; import org.springframework.web.reactive.config.ApiVersionConfigurer; import org.springframework.web.reactive.config.EnableWebFlux; +import org.springframework.web.reactive.config.ResourceHandlerRegistry; import org.springframework.web.reactive.config.WebFluxConfigurer; import org.springframework.web.testfixture.http.server.reactive.bootstrap.HttpServer; +import org.springframework.web.testfixture.http.server.reactive.bootstrap.TomcatHttpServer; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; @@ -73,6 +77,17 @@ public class RequestMappingVersionIntegrationTests extends AbstractRequestMappin .isEqualTo("; rel=\"deprecation\"; type=\"text/html\""); } + @Test// gh-36059 + void staticResourceWithInvalidApiVersion() throws Exception { + startServer((HttpServer) new TomcatHttpServer()); + + String url = "http://localhost:" + this.port + "/cp/test/foo.css"; + RequestEntity requestEntity = RequestEntity.get(url).header("API-Version", "Invalid").build(); + ResponseEntity entity = getRestTemplate().exchange(requestEntity, String.class); + + assertThat(entity.getBody()).isEqualTo("h1 { color:red; }"); + } + private ResponseEntity exchangeWithVersion(String version) { String url = "http://localhost:" + this.port; RequestEntity requestEntity = RequestEntity.get(url).header("API-Version", version).build(); @@ -93,6 +108,12 @@ public class RequestMappingVersionIntegrationTests extends AbstractRequestMappin .addSupportedVersions("1", "1.1", "1.3", "1.6") .setDeprecationHandler(handler); } + + @Override + public void addResourceHandlers(ResourceHandlerRegistry registry) { + registry.addResourceHandler("/cp/**") + .addResourceLocations("classpath:org/springframework/web/reactive/resource/"); + } } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerMapping.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerMapping.java index 60bf1408044..a42566b390c 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerMapping.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerMapping.java @@ -591,20 +591,17 @@ public abstract class AbstractHandlerMapping extends WebApplicationObjectSupport } private ApiVersionHolder initApiVersion(HttpServletRequest request) { - ApiVersionHolder versionHolder = (ApiVersionHolder) request.getAttribute(API_VERSION_ATTRIBUTE); - if (versionHolder == null) { - if (this.versionStrategy == null) { - versionHolder = ApiVersionHolder.EMPTY; + ApiVersionHolder versionHolder; + if (this.versionStrategy == null) { + versionHolder = ApiVersionHolder.EMPTY; + } + else { + try { + Comparable version = this.versionStrategy.resolveParseAndValidateVersion(request); + versionHolder = ApiVersionHolder.fromVersion(version); } - else { - Comparable version; - try { - version = this.versionStrategy.resolveParseAndValidateVersion(request); - versionHolder = ApiVersionHolder.fromVersion(version); - } - catch (RuntimeException ex) { - versionHolder = ApiVersionHolder.fromError(ex); - } + catch (RuntimeException ex) { + versionHolder = ApiVersionHolder.fromError(ex); } } request.setAttribute(API_VERSION_ATTRIBUTE, versionHolder); diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/ResourceHttpRequestHandlerIntegrationTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/ResourceHttpRequestHandlerIntegrationTests.java index 4fcdab8d061..f98e0eb8dc6 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/ResourceHttpRequestHandlerIntegrationTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/resource/ResourceHttpRequestHandlerIntegrationTests.java @@ -28,6 +28,7 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; +import org.springframework.context.annotation.Configuration; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.FileSystemResource; import org.springframework.core.io.UrlResource; @@ -36,6 +37,7 @@ import org.springframework.http.converter.json.JacksonJsonHttpMessageConverter; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; import org.springframework.web.servlet.DispatcherServlet; +import org.springframework.web.servlet.config.annotation.ApiVersionConfigurer; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.PathMatchConfigurer; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; @@ -121,7 +123,7 @@ class ResourceHttpRequestHandlerIntegrationTests { } @Test - void testNoResourceFoundException() throws Exception { + void noResourceFoundException() throws Exception { AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext(); context.setServletConfig(this.servletConfig); context.register(WebConfig.class); @@ -149,6 +151,29 @@ class ResourceHttpRequestHandlerIntegrationTests { """); } + @Test // gh-36059 + void invalidApiVersion() throws Exception { + AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext(); + context.setServletConfig(this.servletConfig); + context.register(WebConfig.class, VersionConfig.class); + context.refresh(); + + DispatcherServlet servlet = new DispatcherServlet(); + servlet.setApplicationContext(context); + servlet.init(this.servletConfig); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/cp/test/foo.css"); + MockHttpServletResponse response = new MockHttpServletResponse(); + + request.addHeader("API-Version", "Invalid"); + + servlet.service(request, response); + + assertThat(response.getStatus()).isEqualTo(200); + assertThat(response.getContentType()).isEqualTo("text/css"); + assertThat(response.getContentAsString()).isEqualTo("h1 { color:red; }"); + } + private DispatcherServlet initDispatcherServlet( boolean usePathPatterns, boolean decodingUrlPathHelper, Class... configClasses) throws ServletException { @@ -257,4 +282,14 @@ class ResourceHttpRequestHandlerIntegrationTests { private static class GlobalExceptionHandler extends ResponseEntityExceptionHandler { } + + @Configuration + static class VersionConfig implements WebMvcConfigurer { + + @Override + public void configureApiVersioning(ApiVersionConfigurer configurer) { + configurer.useRequestHeader("API-Version"); + } + } + }