Consistently validate API version

Closes gh-35082
This commit is contained in:
rstoyanchev
2025-06-23 18:03:56 +01:00
parent a0f9872746
commit 0eec1dc636
4 changed files with 37 additions and 10 deletions
@@ -105,10 +105,6 @@ public final class VersionRequestCondition extends AbstractRequestCondition<Vers
@Override
public @Nullable VersionRequestCondition getMatchingCondition(ServerWebExchange exchange) {
if (this.version == null) {
return this;
}
Comparable<?> requestVersion = exchange.getAttribute(VERSION_ATTRIBUTE_NAME);
if (requestVersion == null) {
String value = this.versionStrategy.resolveVersion(exchange);
@@ -118,7 +114,7 @@ public final class VersionRequestCondition extends AbstractRequestCondition<Vers
exchange.getAttributes().put(VERSION_ATTRIBUTE_NAME, (requestVersion));
}
if (requestVersion == NO_VERSION_ATTRIBUTE) {
if (this.version == null || requestVersion == NO_VERSION_ATTRIBUTE) {
return this;
}
@@ -23,6 +23,8 @@ import org.jspecify.annotations.Nullable;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.web.accept.InvalidApiVersionException;
import org.springframework.web.accept.MissingApiVersionException;
import org.springframework.web.accept.NotAcceptableApiVersionException;
import org.springframework.web.accept.SemanticApiVersionParser;
import org.springframework.web.reactive.accept.DefaultApiVersionStrategy;
@@ -90,6 +92,21 @@ public class VersionRequestConditionTests {
testMatch("v1.3", condition, true, false);
}
@Test
void notVersionedMatch() {
VersionRequestCondition condition = new VersionRequestCondition(null, this.strategy);
this.strategy.addSupportedVersion("1.1", "1.3");
testMatch("v1.1", condition, true, false);
testMatch("v1.3", condition, true, false);
assertThatThrownBy(() -> condition.getMatchingCondition(exchangeWithVersion("1.2")))
.isInstanceOf(InvalidApiVersionException.class);
assertThatThrownBy(() -> condition.getMatchingCondition(MockServerWebExchange.from(MockServerHttpRequest.get("/"))))
.isInstanceOf(MissingApiVersionException.class);
}
private void testMatch(
String requestVersion, VersionRequestCondition condition, boolean matches, boolean notAcceptable) {
@@ -27,6 +27,7 @@ import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.accept.ApiVersionStrategy;
import org.springframework.web.accept.InvalidApiVersionException;
import org.springframework.web.accept.MissingApiVersionException;
import org.springframework.web.accept.NotAcceptableApiVersionException;
import org.springframework.web.bind.annotation.RequestMapping;
@@ -104,10 +105,6 @@ public final class VersionRequestCondition extends AbstractRequestCondition<Vers
@Override
public @Nullable VersionRequestCondition getMatchingCondition(HttpServletRequest request) {
if (this.version == null) {
return this;
}
Comparable<?> requestVersion = (Comparable<?>) request.getAttribute(VERSION_ATTRIBUTE_NAME);
if (requestVersion == null) {
String value = this.versionStrategy.resolveVersion(request);
@@ -117,7 +114,7 @@ public final class VersionRequestCondition extends AbstractRequestCondition<Vers
request.setAttribute(VERSION_ATTRIBUTE_NAME, (requestVersion));
}
if (requestVersion == NO_VERSION_ATTRIBUTE) {
if (this.version == null || requestVersion == NO_VERSION_ATTRIBUTE) {
return this;
}
@@ -24,6 +24,8 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.web.accept.DefaultApiVersionStrategy;
import org.springframework.web.accept.InvalidApiVersionException;
import org.springframework.web.accept.MissingApiVersionException;
import org.springframework.web.accept.NotAcceptableApiVersionException;
import org.springframework.web.accept.SemanticApiVersionParser;
import org.springframework.web.testfixture.servlet.MockHttpServletRequest;
@@ -88,6 +90,21 @@ public class VersionRequestConditionTests {
testMatch("v1.3", condition, true, false);
}
@Test
void notVersionedMatch() {
VersionRequestCondition condition = new VersionRequestCondition(null, this.strategy);
this.strategy.addSupportedVersion("1.1", "1.3");
testMatch("v1.1", condition, true, false);
testMatch("v1.3", condition, true, false);
assertThatThrownBy(() -> condition.getMatchingCondition(requestWithVersion("1.2")))
.isInstanceOf(InvalidApiVersionException.class);
assertThatThrownBy(() -> condition.getMatchingCondition(new MockHttpServletRequest("GET", "/path")))
.isInstanceOf(MissingApiVersionException.class);
}
private void testMatch(
String requestVersion, VersionRequestCondition condition, boolean matches, boolean notAcceptable) {