More accurate checks for presence of MediaType.ALL

Typically a straight up equals as well as Collections#contains
checks for MediaType.ALL is susceptible to the presence of
media type parameters.

This commits adds equalsTypeAndSubtype as well as an
isPresentIn(Collection<MimeType>) methods to MimeType to faciliate
with checks for MediaType.ALL.

Issue: SPR-17550
This commit is contained in:
Rossen Stoyanchev
2019-01-02 14:32:50 -05:00
parent 1cb9f2c7b2
commit 4b24bcb799
10 changed files with 111 additions and 38 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2019 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.
@@ -17,6 +17,7 @@
package org.springframework.web.reactive.result;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.LinkedHashSet;
import java.util.List;
@@ -47,7 +48,8 @@ import org.springframework.web.server.ServerWebExchange;
*/
public abstract class HandlerResultHandlerSupport implements Ordered {
private static final MediaType MEDIA_TYPE_APPLICATION_ALL = new MediaType("application");
private static final List<MediaType> ALL_APPLICATION_MEDIA_TYPES =
Arrays.asList(MediaType.ALL, new MediaType("application"));
protected final Log logger = LogFactory.getLog(getClass());
@@ -147,7 +149,7 @@ public abstract class HandlerResultHandlerSupport implements Ordered {
selected = mediaType;
break;
}
else if (mediaType.equals(MediaType.ALL) || mediaType.equals(MEDIA_TYPE_APPLICATION_ALL)) {
else if (mediaType.isPresentIn(ALL_APPLICATION_MEDIA_TYPES)) {
selected = MediaType.APPLICATION_OCTET_STREAM;
break;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2019 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.
@@ -33,6 +33,7 @@ import org.springframework.web.reactive.accept.RequestedContentTypeResolver;
import org.springframework.web.reactive.accept.RequestedContentTypeResolverBuilder;
import org.springframework.web.server.NotAcceptableStatusException;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.UnsupportedMediaTypeStatusException;
/**
* A logical disjunction (' || ') request condition to match a request's 'Accept' header
@@ -48,6 +49,8 @@ public final class ProducesRequestCondition extends AbstractRequestCondition<Pro
private static final ProducesRequestCondition PRE_FLIGHT_MATCH = new ProducesRequestCondition();
private static final ProducesRequestCondition EMPTY_CONDITION = new ProducesRequestCondition();
private final List<ProduceMediaTypeExpression> mediaTypeAllList =
Collections.singletonList(new ProduceMediaTypeExpression(MediaType.ALL_VALUE));
@@ -192,7 +195,20 @@ public final class ProducesRequestCondition extends AbstractRequestCondition<Pro
}
Set<ProduceMediaTypeExpression> result = new LinkedHashSet<>(this.expressions);
result.removeIf(expression -> !expression.match(exchange));
return (!result.isEmpty() ? new ProducesRequestCondition(result, this.contentTypeResolver) : null);
if (!result.isEmpty()) {
return new ProducesRequestCondition(result, this.contentTypeResolver);
}
else {
try {
if (MediaType.ALL.isPresentIn(getAcceptedMediaTypes(exchange))) {
return EMPTY_CONDITION;
}
}
catch (NotAcceptableStatusException | UnsupportedMediaTypeStatusException ex) {
// Ignore
}
}
return null;
}
/**

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2019 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.
@@ -39,7 +39,7 @@ import static org.springframework.mock.http.server.reactive.test.MockServerHttpR
public class ProducesRequestConditionTests {
@Test
public void match() throws Exception {
public void match() {
MockServerWebExchange exchange = MockServerWebExchange.from(get("/").header("Accept", "text/plain"));
ProducesRequestCondition condition = new ProducesRequestCondition("text/plain");
@@ -47,7 +47,7 @@ public class ProducesRequestConditionTests {
}
@Test
public void matchNegated() throws Exception {
public void matchNegated() {
MockServerWebExchange exchange = MockServerWebExchange.from(get("/").header("Accept", "text/plain"));
ProducesRequestCondition condition = new ProducesRequestCondition("!text/plain");
@@ -55,13 +55,13 @@ public class ProducesRequestConditionTests {
}
@Test
public void getProducibleMediaTypes() throws Exception {
public void getProducibleMediaTypes() {
ProducesRequestCondition condition = new ProducesRequestCondition("!application/xml");
assertEquals(Collections.emptySet(), condition.getProducibleMediaTypes());
}
@Test
public void matchWildcard() throws Exception {
public void matchWildcard() {
MockServerWebExchange exchange = MockServerWebExchange.from(get("/").header("Accept", "text/plain"));
ProducesRequestCondition condition = new ProducesRequestCondition("text/*");
@@ -69,7 +69,7 @@ public class ProducesRequestConditionTests {
}
@Test
public void matchMultiple() throws Exception {
public void matchMultiple() {
MockServerWebExchange exchange = MockServerWebExchange.from(get("/").header("Accept", "text/plain"));
ProducesRequestCondition condition = new ProducesRequestCondition("text/plain", "application/xml");
@@ -77,7 +77,7 @@ public class ProducesRequestConditionTests {
}
@Test
public void matchSingle() throws Exception {
public void matchSingle() {
MockServerWebExchange exchange = MockServerWebExchange.from(get("/").header("Accept", "application/xml"));
ProducesRequestCondition condition = new ProducesRequestCondition("text/plain");
@@ -85,7 +85,7 @@ public class ProducesRequestConditionTests {
}
@Test
public void matchParseError() throws Exception {
public void matchParseError() {
MockServerWebExchange exchange = MockServerWebExchange.from(get("/").header("Accept", "bogus"));
ProducesRequestCondition condition = new ProducesRequestCondition("text/plain");
@@ -93,15 +93,26 @@ public class ProducesRequestConditionTests {
}
@Test
public void matchParseErrorWithNegation() throws Exception {
public void matchParseErrorWithNegation() {
MockServerWebExchange exchange = MockServerWebExchange.from(get("/").header("Accept", "bogus"));
ProducesRequestCondition condition = new ProducesRequestCondition("!text/plain");
assertNull(condition.getMatchingCondition(exchange));
}
@Test // SPR-17550
public void matchWithNegationAndMediaTypeAllWithQualityParameter() {
ProducesRequestCondition condition = new ProducesRequestCondition("!application/json");
MockServerWebExchange exchange = MockServerWebExchange.from(get("/").header("Accept",
"text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8"));
assertNotNull(condition.getMatchingCondition(exchange));
}
@Test
public void compareTo() throws Exception {
public void compareTo() {
ProducesRequestCondition html = new ProducesRequestCondition("text/html");
ProducesRequestCondition xml = new ProducesRequestCondition("application/xml");
ProducesRequestCondition none = new ProducesRequestCondition();
@@ -136,7 +147,7 @@ public class ProducesRequestConditionTests {
}
@Test
public void compareToWithSingleExpression() throws Exception {
public void compareToWithSingleExpression() {
MockServerWebExchange exchange = MockServerWebExchange.from(get("/").header("Accept", "text/plain"));
ProducesRequestCondition condition1 = new ProducesRequestCondition("text/plain");
@@ -150,7 +161,7 @@ public class ProducesRequestConditionTests {
}
@Test
public void compareToMultipleExpressions() throws Exception {
public void compareToMultipleExpressions() {
ProducesRequestCondition condition1 = new ProducesRequestCondition("*/*", "text/plain");
ProducesRequestCondition condition2 = new ProducesRequestCondition("text/*", "text/plain;q=0.7");
@@ -164,7 +175,7 @@ public class ProducesRequestConditionTests {
}
@Test
public void compareToMultipleExpressionsAndMultipleAcceptHeaderValues() throws Exception {
public void compareToMultipleExpressionsAndMultipleAcceptHeaderValues() {
ProducesRequestCondition condition1 = new ProducesRequestCondition("text/*", "text/plain");
ProducesRequestCondition condition2 = new ProducesRequestCondition("application/*", "application/xml");
@@ -190,7 +201,7 @@ public class ProducesRequestConditionTests {
// SPR-8536
@Test
public void compareToMediaTypeAll() throws Exception {
public void compareToMediaTypeAll() {
MockServerWebExchange exchange = MockServerWebExchange.from(get("/"));
ProducesRequestCondition condition1 = new ProducesRequestCondition();
@@ -226,7 +237,7 @@ public class ProducesRequestConditionTests {
// SPR-9021
@Test
public void compareToMediaTypeAllWithParameter() throws Exception {
public void compareToMediaTypeAllWithParameter() {
MockServerWebExchange exchange = MockServerWebExchange.from(get("/").header("Accept", "*/*;q=0.9"));
ProducesRequestCondition condition1 = new ProducesRequestCondition();
@@ -237,7 +248,7 @@ public class ProducesRequestConditionTests {
}
@Test
public void compareToEqualMatch() throws Exception {
public void compareToEqualMatch() {
MockServerWebExchange exchange = MockServerWebExchange.from(get("/").header("Accept", "text/*"));
ProducesRequestCondition condition1 = new ProducesRequestCondition("text/plain");
@@ -251,7 +262,7 @@ public class ProducesRequestConditionTests {
}
@Test
public void combine() throws Exception {
public void combine() {
ProducesRequestCondition condition1 = new ProducesRequestCondition("text/plain");
ProducesRequestCondition condition2 = new ProducesRequestCondition("application/xml");
@@ -260,7 +271,7 @@ public class ProducesRequestConditionTests {
}
@Test
public void combineWithDefault() throws Exception {
public void combineWithDefault() {
ProducesRequestCondition condition1 = new ProducesRequestCondition("text/plain");
ProducesRequestCondition condition2 = new ProducesRequestCondition();
@@ -269,7 +280,7 @@ public class ProducesRequestConditionTests {
}
@Test
public void instantiateWithProducesAndHeaderConditions() throws Exception {
public void instantiateWithProducesAndHeaderConditions() {
String[] produces = new String[] {"text/plain"};
String[] headers = new String[]{"foo=bar", "accept=application/xml,application/pdf"};
ProducesRequestCondition condition = new ProducesRequestCondition(produces, headers);
@@ -278,7 +289,7 @@ public class ProducesRequestConditionTests {
}
@Test
public void getMatchingCondition() throws Exception {
public void getMatchingCondition() {
MockServerWebExchange exchange = MockServerWebExchange.from(get("/").header("Accept", "text/plain"));
ProducesRequestCondition condition = new ProducesRequestCondition("text/plain", "application/xml");