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
This commit is contained in:
Brian Clozel 2023-03-15 10:16:27 +01:00
parent 1de36abc07
commit 2a5eab4b89
2 changed files with 25 additions and 12 deletions

View File

@ -93,7 +93,7 @@ public class RequestedContentTypeResolverBuilder {
return exchange -> {
for (RequestedContentTypeResolver resolver : resolvers) {
List<MediaType> mediaTypes = resolver.resolveMediaTypes(exchange);
if (mediaTypes.equals(RequestedContentTypeResolver.MEDIA_TYPE_ALL_LIST)) {
if (isMediaTypeAll(mediaTypes)) {
continue;
}
return mediaTypes;
@ -102,6 +102,11 @@ public class RequestedContentTypeResolverBuilder {
};
}
private boolean isMediaTypeAll(List<MediaType> mediaTypes) {
return mediaTypes.size() == 1
&& mediaTypes.get(0).removeQualityValue().equals(MediaType.ALL);
}
/**
* Helper to create and configure {@link ParameterContentTypeResolver}.

View File

@ -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 @@ import static org.assertj.core.api.Assertions.assertThat;
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 class RequestedContentTypeResolverBuilderTests {
}
@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 class RequestedContentTypeResolverBuilderTests {
}
@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 class RequestedContentTypeResolverBuilderTests {
}
@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 class RequestedContentTypeResolverBuilderTests {
}
@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 class RequestedContentTypeResolverBuilderTests {
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<MediaType> mediaTypes = resolver.resolveMediaTypes(exchange);
assertThat(mediaTypes).isEqualTo(Collections.singletonList(MediaType.APPLICATION_JSON));
}
}