From 2a5eab4b899dcb2000655039b6b754715348d66f Mon Sep 17 00:00:00 2001 From: Brian Clozel Date: Wed, 15 Mar 2023 10:16:27 +0100 Subject: [PATCH] Ignore quality factor when filtering out "*/*" Prior to this commit, the `RequestedContentTypeResolverBuilder` would create a `RequestedContentTypeResolver` that internally delegates to a list of resolvers. Each resolver would either return the list of requested media types, or a singleton list with the "*/*" media type; in this case this signals that the resolver cannot find a specific media type requested and that we should continue with the next resolver in the list. Media Types returned by resolvers can contain parameters, such as the quality factor. If the HTTP client requests "*/*;q=0.8", the `HeaderContentTypeResolver` will return this as a singleton list. While this has been resolved from the request, such a media type should not be selected over other media types that could be returned by other resolvers. This commit changes the `RequestedContentTypeResolverBuilder` so that it does not select "*/*;q=0.8" as the requested media type, but instead continues delegating to other resolvers in the list. This means we need to remove the quality factor before comparing it to the "*/*" for equality check. Fixes gh-29915 --- .../RequestedContentTypeResolverBuilder.java | 7 ++++- ...uestedContentTypeResolverBuilderTests.java | 30 ++++++++++++------- 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/accept/RequestedContentTypeResolverBuilder.java b/spring-webflux/src/main/java/org/springframework/web/reactive/accept/RequestedContentTypeResolverBuilder.java index e94f25a2d741..c85a021351e3 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/accept/RequestedContentTypeResolverBuilder.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/accept/RequestedContentTypeResolverBuilder.java @@ -93,7 +93,7 @@ public RequestedContentTypeResolver build() { return exchange -> { for (RequestedContentTypeResolver resolver : resolvers) { List mediaTypes = resolver.resolveMediaTypes(exchange); - if (mediaTypes.equals(RequestedContentTypeResolver.MEDIA_TYPE_ALL_LIST)) { + if (isMediaTypeAll(mediaTypes)) { continue; } return mediaTypes; @@ -102,6 +102,11 @@ public RequestedContentTypeResolver build() { }; } + private boolean isMediaTypeAll(List mediaTypes) { + return mediaTypes.size() == 1 + && mediaTypes.get(0).removeQualityValue().equals(MediaType.ALL); + } + /** * Helper to create and configure {@link ParameterContentTypeResolver}. diff --git a/spring-webflux/src/test/java/org/springframework/web/reactive/accept/RequestedContentTypeResolverBuilderTests.java b/spring-webflux/src/test/java/org/springframework/web/reactive/accept/RequestedContentTypeResolverBuilderTests.java index f4b7dc36fab5..f0dccf848b6d 100644 --- a/spring-webflux/src/test/java/org/springframework/web/reactive/accept/RequestedContentTypeResolverBuilderTests.java +++ b/spring-webflux/src/test/java/org/springframework/web/reactive/accept/RequestedContentTypeResolverBuilderTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2019 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. @@ -34,8 +34,7 @@ public class RequestedContentTypeResolverBuilderTests { @Test - public void defaultSettings() throws Exception { - + void defaultSettings() { RequestedContentTypeResolver resolver = new RequestedContentTypeResolverBuilder().build(); MockServerWebExchange exchange = MockServerWebExchange.from( MockServerHttpRequest.get("/flower").accept(MediaType.IMAGE_GIF)); @@ -45,8 +44,7 @@ public void defaultSettings() throws Exception { } @Test - public void parameterResolver() throws Exception { - + void parameterResolver() { RequestedContentTypeResolverBuilder builder = new RequestedContentTypeResolverBuilder(); builder.parameterResolver().mediaType("json", MediaType.APPLICATION_JSON); RequestedContentTypeResolver resolver = builder.build(); @@ -58,8 +56,7 @@ public void parameterResolver() throws Exception { } @Test - public void parameterResolverWithCustomParamName() throws Exception { - + void parameterResolverWithCustomParamName() { RequestedContentTypeResolverBuilder builder = new RequestedContentTypeResolverBuilder(); builder.parameterResolver().mediaType("json", MediaType.APPLICATION_JSON).parameterName("s"); RequestedContentTypeResolver resolver = builder.build(); @@ -71,8 +68,7 @@ public void parameterResolverWithCustomParamName() throws Exception { } @Test // SPR-10513 - public void fixedResolver() throws Exception { - + void fixedResolver() { RequestedContentTypeResolverBuilder builder = new RequestedContentTypeResolverBuilder(); builder.fixedResolver(MediaType.APPLICATION_JSON); RequestedContentTypeResolver resolver = builder.build(); @@ -84,8 +80,7 @@ public void fixedResolver() throws Exception { } @Test // SPR-12286 - public void resolver() throws Exception { - + void resolver() { RequestedContentTypeResolverBuilder builder = new RequestedContentTypeResolverBuilder(); builder.resolver(new FixedContentTypeResolver(MediaType.APPLICATION_JSON)); RequestedContentTypeResolver resolver = builder.build(); @@ -99,4 +94,17 @@ public void resolver() throws Exception { assertThat(mediaTypes).isEqualTo(Collections.singletonList(MediaType.APPLICATION_JSON)); } + @Test + void removeQualityFactorForMediaTypeAllChecks() { + RequestedContentTypeResolverBuilder builder = new RequestedContentTypeResolverBuilder(); + builder.resolver(new HeaderContentTypeResolver()); + builder.resolver(new FixedContentTypeResolver(MediaType.APPLICATION_JSON)); + RequestedContentTypeResolver resolver = builder.build(); + + MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/") + .accept(MediaType.valueOf("*/*;q=0.8"))); + List mediaTypes = resolver.resolveMediaTypes(exchange); + assertThat(mediaTypes).isEqualTo(Collections.singletonList(MediaType.APPLICATION_JSON)); + } + }