Always match the links endpoint with GET

The links endpoint only supports GET, so its matcher is now hardcoded
to GET. withHttpMethod(...) continues to apply only to endpoint paths
and the behaviour is documented on its javadoc.

Signed-off-by: Lee JiWon <dlwldnjs1009@gmail.com>

See gh-50095
This commit is contained in:
Lee JiWon
2026-04-30 13:34:11 +01:00
committed by Andy Wilkinson
parent d2b62bc64f
commit 2d3273e078
4 changed files with 42 additions and 15 deletions
@@ -316,6 +316,8 @@ public final class EndpointRequest {
/**
* Restricts the matcher to only consider requests with a particular http method.
* <p>
* The links endpoint, if included, is always matched using {@code GET}.
* @param httpMethod the http method to include
* @return a copy of the matcher further restricted to only match requests with
* the specified http method
@@ -373,9 +375,9 @@ public final class EndpointRequest {
String linksPath = getLinksPath(properties.getBasePath());
if (linksPath != null) {
List<ServerWebExchangeMatcher> linksMatchers = new ArrayList<>();
linksMatchers.add(new PathPatternParserServerWebExchangeMatcher(linksPath));
linksMatchers.add(new PathPatternParserServerWebExchangeMatcher(linksPath, HttpMethod.GET));
if (!linksPath.endsWith("/")) {
linksMatchers.add(new PathPatternParserServerWebExchangeMatcher(linksPath + "/"));
linksMatchers.add(new PathPatternParserServerWebExchangeMatcher(linksPath + "/", HttpMethod.GET));
}
return new OrServerWebExchangeMatcher(linksMatchers);
}
@@ -227,9 +227,9 @@ public final class EndpointRequest {
protected List<RequestMatcher> getLinksMatchers(RequestMatcherFactory requestMatcherFactory,
RequestMatcherProvider matcherProvider, String linksPath) {
List<RequestMatcher> linksMatchers = new ArrayList<>();
linksMatchers.add(requestMatcherFactory.antPath(matcherProvider, null, linksPath));
linksMatchers.add(requestMatcherFactory.antPath(matcherProvider, HttpMethod.GET, linksPath));
if (!linksPath.endsWith("/")) {
linksMatchers.add(requestMatcherFactory.antPath(matcherProvider, null, linksPath, "/"));
linksMatchers.add(requestMatcherFactory.antPath(matcherProvider, HttpMethod.GET, linksPath, "/"));
}
return linksMatchers;
}
@@ -350,6 +350,8 @@ public final class EndpointRequest {
/**
* Restricts the matcher to only consider requests with a particular HTTP method.
* <p>
* The links endpoint, if included, is always matched using {@code GET}.
* @param httpMethod the HTTP method to include
* @return a copy of the matcher further restricted to only match requests with
* the specified HTTP method
@@ -75,6 +75,15 @@ class EndpointRequestTests {
assertMatcher(matcher, "/actuator").doesNotMatch(HttpMethod.GET, "/actuator/foo");
}
@Test
void toAnyEndpointWithHttpMethodShouldUseGetForLinks() {
ServerWebExchangeMatcher matcher = EndpointRequest.toAnyEndpoint().withHttpMethod(HttpMethod.POST);
assertMatcher(matcher, "/actuator").matches(HttpMethod.GET, "/actuator");
assertMatcher(matcher, "/actuator").doesNotMatch(HttpMethod.POST, "/actuator");
assertMatcher(matcher, "/actuator").matches(HttpMethod.GET, "/actuator/");
assertMatcher(matcher, "/actuator").doesNotMatch(HttpMethod.POST, "/actuator/");
}
@Test
void toAnyEndpointShouldMatchEndpointPathWithTrailingSlash() {
ServerWebExchangeMatcher matcher = EndpointRequest.toAnyEndpoint();
@@ -140,8 +149,10 @@ class EndpointRequestTests {
ServerWebExchangeMatcher matcher = EndpointRequest.toLinks();
assertMatcher(matcher).doesNotMatch("/actuator/foo");
assertMatcher(matcher).doesNotMatch("/actuator/bar");
assertMatcher(matcher).matches("/actuator");
assertMatcher(matcher).matches("/actuator/");
assertMatcher(matcher).matches(HttpMethod.GET, "/actuator");
assertMatcher(matcher).doesNotMatch(HttpMethod.POST, "/actuator");
assertMatcher(matcher).matches(HttpMethod.GET, "/actuator/");
assertMatcher(matcher).doesNotMatch(HttpMethod.POST, "/actuator/");
}
@Test
@@ -64,7 +64,7 @@ class EndpointRequestTests {
assertMatcher(matcher, "/actuator").matches("/actuator/foo/zoo/");
assertMatcher(matcher, "/actuator").matches("/actuator/bar");
assertMatcher(matcher, "/actuator").matches("/actuator/bar/baz");
assertMatcher(matcher, "/actuator").matches("/actuator");
assertMatcher(matcher, "/actuator").matches(HttpMethod.GET, "/actuator");
}
@Test
@@ -75,12 +75,22 @@ class EndpointRequestTests {
assertMatcher(matcher, "/actuator").doesNotMatch(HttpMethod.GET, "/actuator/foo");
}
@Test
void toAnyEndpointWithHttpMethodShouldUseGetForLinks() {
EndpointRequest.EndpointRequestMatcher matcher = EndpointRequest.toAnyEndpoint()
.withHttpMethod(HttpMethod.POST);
assertMatcher(matcher, "/actuator").matches(HttpMethod.GET, "/actuator");
assertMatcher(matcher, "/actuator").doesNotMatch(HttpMethod.POST, "/actuator");
assertMatcher(matcher, "/actuator").matches(HttpMethod.GET, "/actuator/");
assertMatcher(matcher, "/actuator").doesNotMatch(HttpMethod.POST, "/actuator/");
}
@Test
void toAnyEndpointShouldMatchEndpointPathWithTrailingSlash() {
RequestMatcher matcher = EndpointRequest.toAnyEndpoint();
assertMatcher(matcher, "/actuator").matches("/actuator/foo/");
assertMatcher(matcher, "/actuator").matches("/actuator/bar/");
assertMatcher(matcher, "/actuator").matches("/actuator/");
assertMatcher(matcher, "/actuator").matches(HttpMethod.GET, "/actuator/");
}
@Test
@@ -97,7 +107,7 @@ class EndpointRequestTests {
RequestMatcher matcher = EndpointRequest.toAnyEndpoint();
RequestMatcherAssert assertMatcher = assertMatcher(matcher, mockPathMappedEndpoints(""), null,
WebServerNamespace.MANAGEMENT);
assertMatcher.matches("/");
assertMatcher.matches(HttpMethod.GET, "/");
assertMatcher.matches("/foo");
}
@@ -112,7 +122,7 @@ class EndpointRequestTests {
RequestMatcher matcher = EndpointRequest.toAnyEndpoint();
assertMatcher(matcher, "/actuator").matches("/actuator/foo");
assertMatcher(matcher, "/actuator").matches("/actuator/bar");
assertMatcher(matcher, "/actuator").matches("/actuator");
assertMatcher(matcher, "/actuator").matches(HttpMethod.GET, "/actuator");
assertMatcher(matcher, "/actuator").doesNotMatch("/actuator/baz");
}
@@ -147,8 +157,10 @@ class EndpointRequestTests {
RequestMatcher matcher = EndpointRequest.toLinks();
assertMatcher(matcher).doesNotMatch("/actuator/foo");
assertMatcher(matcher).doesNotMatch("/actuator/bar");
assertMatcher(matcher).matches("/actuator");
assertMatcher(matcher).matches("/actuator/");
assertMatcher(matcher).matches(HttpMethod.GET, "/actuator");
assertMatcher(matcher).doesNotMatch(HttpMethod.POST, "/actuator");
assertMatcher(matcher).matches(HttpMethod.GET, "/actuator/");
assertMatcher(matcher).doesNotMatch(HttpMethod.POST, "/actuator/");
}
@Test
@@ -165,7 +177,7 @@ class EndpointRequestTests {
RequestMatcher matcher = EndpointRequest.toLinks();
RequestMatcherAssert assertMatcher = assertMatcher(matcher, mockPathMappedEndpoints(""), null,
WebServerNamespace.MANAGEMENT);
assertMatcher.matches("/");
assertMatcher.matches(HttpMethod.GET, "/");
assertMatcher.doesNotMatch("/foo");
}
@@ -180,7 +192,7 @@ class EndpointRequestTests {
assertMatcher(matcher, pathMappedEndpoints).doesNotMatch("/actuator/foo");
assertMatcher(matcher, pathMappedEndpoints).doesNotMatch("/actuator/baz");
assertMatcher(matcher).matches("/actuator/bar");
assertMatcher(matcher).matches("/actuator");
assertMatcher(matcher).matches(HttpMethod.GET, "/actuator");
}
@Test
@@ -195,7 +207,7 @@ class EndpointRequestTests {
RequestMatcher matcher = EndpointRequest.toAnyEndpoint().excluding("foo");
assertMatcher(matcher).doesNotMatch("/actuator/foo");
assertMatcher(matcher).matches("/actuator/bar");
assertMatcher(matcher).matches("/actuator");
assertMatcher(matcher).matches(HttpMethod.GET, "/actuator");
}
@Test