mirror of
https://github.com/spring-projects/spring-boot.git
synced 2026-09-24 02:09:05 +00:00
Fix EndpointRequest links matching for separate management port
When management.endpoints.web.base-path is empty and management runs on a different port, EndpointRequest.toLinks() and toAnyEndpoint() do not match the links endpoint consistently. Derive the links path based on the management port type on both servlet and reactive sides, and add regression tests for each implementation. See gh-49591 Signed-off-by: bbbbooo <hyeons1213@gmail.com>
This commit is contained in:
+20
-5
@@ -228,6 +228,13 @@ public final class EndpointRequest {
|
||||
&& applicationContext.getParent() == null;
|
||||
}
|
||||
|
||||
protected final String getLinksPath(String basePath) {
|
||||
if (StringUtils.hasText(basePath)) {
|
||||
return basePath;
|
||||
}
|
||||
return (this.managementPortType == ManagementPortType.DIFFERENT) ? "/" : null;
|
||||
}
|
||||
|
||||
protected final String toString(List<Object> endpoints, String emptyValue) {
|
||||
return (!endpoints.isEmpty()) ? endpoints.stream()
|
||||
.map(this::getEndpointId)
|
||||
@@ -326,7 +333,8 @@ public final class EndpointRequest {
|
||||
streamPaths(this.includes, endpoints).forEach(paths::add);
|
||||
streamPaths(this.excludes, endpoints).forEach(paths::remove);
|
||||
List<ServerWebExchangeMatcher> delegateMatchers = getDelegateMatchers(paths, this.httpMethod);
|
||||
if (this.includeLinks && StringUtils.hasText(endpoints.getBasePath())) {
|
||||
String linksPath = getLinksPath(endpoints.getBasePath());
|
||||
if (this.includeLinks && linksPath != null) {
|
||||
delegateMatchers.add(new LinksServerWebExchangeMatcher());
|
||||
}
|
||||
if (delegateMatchers.isEmpty()) {
|
||||
@@ -362,10 +370,17 @@ public final class EndpointRequest {
|
||||
|
||||
@Override
|
||||
protected ServerWebExchangeMatcher createDelegate(WebEndpointProperties properties) {
|
||||
if (StringUtils.hasText(properties.getBasePath())) {
|
||||
return new OrServerWebExchangeMatcher(
|
||||
new PathPatternParserServerWebExchangeMatcher(properties.getBasePath()),
|
||||
new PathPatternParserServerWebExchangeMatcher(properties.getBasePath() + "/"));
|
||||
String linksPath = getLinksPath(properties.getBasePath());
|
||||
if (linksPath != null) {
|
||||
List<ServerWebExchangeMatcher> linksMatchers = new ArrayList<>();
|
||||
linksMatchers.add(new PathPatternParserServerWebExchangeMatcher(linksPath));
|
||||
if ("/".equals(linksPath)) {
|
||||
linksMatchers.add(new PathPatternParserServerWebExchangeMatcher(""));
|
||||
}
|
||||
else {
|
||||
linksMatchers.add(new PathPatternParserServerWebExchangeMatcher(linksPath + "/"));
|
||||
}
|
||||
return new OrServerWebExchangeMatcher(linksMatchers);
|
||||
}
|
||||
return EMPTY_MATCHER;
|
||||
}
|
||||
|
||||
+23
-8
@@ -225,13 +225,27 @@ public final class EndpointRequest {
|
||||
}
|
||||
|
||||
protected List<RequestMatcher> getLinksMatchers(RequestMatcherFactory requestMatcherFactory,
|
||||
RequestMatcherProvider matcherProvider, String basePath) {
|
||||
RequestMatcherProvider matcherProvider, String linksPath) {
|
||||
List<RequestMatcher> linksMatchers = new ArrayList<>();
|
||||
linksMatchers.add(requestMatcherFactory.antPath(matcherProvider, null, basePath));
|
||||
linksMatchers.add(requestMatcherFactory.antPath(matcherProvider, null, basePath, "/"));
|
||||
linksMatchers.add(requestMatcherFactory.antPath(matcherProvider, null, linksPath));
|
||||
if (!"/".equals(linksPath)) {
|
||||
linksMatchers.add(requestMatcherFactory.antPath(matcherProvider, null, linksPath, "/"));
|
||||
}
|
||||
return linksMatchers;
|
||||
}
|
||||
|
||||
protected String getLinksPath(WebApplicationContext context, String basePath) {
|
||||
if (StringUtils.hasText(basePath)) {
|
||||
return basePath;
|
||||
}
|
||||
ManagementPortType managementPortType = this.managementPortType;
|
||||
if (managementPortType == null) {
|
||||
managementPortType = ManagementPortType.get(context.getEnvironment());
|
||||
this.managementPortType = managementPortType;
|
||||
}
|
||||
return (managementPortType == ManagementPortType.DIFFERENT) ? "/" : null;
|
||||
}
|
||||
|
||||
protected RequestMatcherProvider getRequestMatcherProvider(WebApplicationContext context) {
|
||||
try {
|
||||
return getRequestMatcherProviderBean(context);
|
||||
@@ -359,8 +373,9 @@ public final class EndpointRequest {
|
||||
List<RequestMatcher> delegateMatchers = getDelegateMatchers(requestMatcherFactory, matcherProvider, paths,
|
||||
this.httpMethod);
|
||||
String basePath = endpoints.getBasePath();
|
||||
if (this.includeLinks && StringUtils.hasText(basePath)) {
|
||||
delegateMatchers.addAll(getLinksMatchers(requestMatcherFactory, matcherProvider, basePath));
|
||||
String linksPath = getLinksPath(context, basePath);
|
||||
if (this.includeLinks && linksPath != null) {
|
||||
delegateMatchers.addAll(getLinksMatchers(requestMatcherFactory, matcherProvider, linksPath));
|
||||
}
|
||||
if (delegateMatchers.isEmpty()) {
|
||||
return EMPTY_MATCHER;
|
||||
@@ -393,10 +408,10 @@ public final class EndpointRequest {
|
||||
protected RequestMatcher createDelegate(WebApplicationContext context,
|
||||
RequestMatcherFactory requestMatcherFactory) {
|
||||
WebEndpointProperties properties = context.getBean(WebEndpointProperties.class);
|
||||
String basePath = properties.getBasePath();
|
||||
if (StringUtils.hasText(basePath)) {
|
||||
String linksPath = getLinksPath(context, properties.getBasePath());
|
||||
if (linksPath != null) {
|
||||
return new OrRequestMatcher(
|
||||
getLinksMatchers(requestMatcherFactory, getRequestMatcherProvider(context), basePath));
|
||||
getLinksMatchers(requestMatcherFactory, getRequestMatcherProvider(context), linksPath));
|
||||
}
|
||||
return EMPTY_MATCHER;
|
||||
}
|
||||
|
||||
+37
-2
@@ -20,6 +20,7 @@ import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.assertj.core.api.AssertDelegateTarget;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -35,6 +36,7 @@ import org.springframework.boot.actuate.endpoint.web.WebServerNamespace;
|
||||
import org.springframework.boot.web.context.WebServerApplicationContext;
|
||||
import org.springframework.boot.web.server.WebServer;
|
||||
import org.springframework.context.support.StaticApplicationContext;
|
||||
import org.springframework.core.env.MapPropertySource;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.server.reactive.ServerHttpRequest;
|
||||
import org.springframework.http.server.reactive.ServerHttpResponse;
|
||||
@@ -91,6 +93,15 @@ class EndpointRequestTests {
|
||||
assertMatcher.matches("/bar");
|
||||
}
|
||||
|
||||
@Test
|
||||
void toAnyEndpointWhenBasePathIsEmptyAndManagementPortDifferentShouldMatchLinks() {
|
||||
ServerWebExchangeMatcher matcher = EndpointRequest.toAnyEndpoint();
|
||||
RequestMatcherAssert assertMatcher = assertMatcher(matcher, mockPathMappedEndpoints(""),
|
||||
WebServerNamespace.MANAGEMENT, true);
|
||||
assertMatcher.matches("/");
|
||||
assertMatcher.matches("/foo");
|
||||
}
|
||||
|
||||
@Test
|
||||
void toAnyEndpointShouldNotMatchOtherPath() {
|
||||
ServerWebExchangeMatcher matcher = EndpointRequest.toAnyEndpoint();
|
||||
@@ -143,6 +154,15 @@ class EndpointRequestTests {
|
||||
assertMatcher.doesNotMatch("/");
|
||||
}
|
||||
|
||||
@Test
|
||||
void toLinksWhenBasePathEmptyAndManagementPortDifferentShouldMatchRoot() {
|
||||
ServerWebExchangeMatcher matcher = EndpointRequest.toLinks();
|
||||
RequestMatcherAssert assertMatcher = assertMatcher(matcher, mockPathMappedEndpoints(""),
|
||||
WebServerNamespace.MANAGEMENT, true);
|
||||
assertMatcher.matches("/");
|
||||
assertMatcher.doesNotMatch("/foo");
|
||||
}
|
||||
|
||||
@Test
|
||||
void excludeByClassShouldNotMatchExcluded() {
|
||||
ServerWebExchangeMatcher matcher = EndpointRequest.toAnyEndpoint()
|
||||
@@ -325,10 +345,25 @@ class EndpointRequestTests {
|
||||
|
||||
private RequestMatcherAssert assertMatcher(ServerWebExchangeMatcher matcher,
|
||||
PathMappedEndpoints pathMappedEndpoints, WebServerNamespace namespace) {
|
||||
return assertMatcher(matcher, pathMappedEndpoints, namespace, false);
|
||||
}
|
||||
|
||||
private RequestMatcherAssert assertMatcher(ServerWebExchangeMatcher matcher,
|
||||
PathMappedEndpoints pathMappedEndpoints, WebServerNamespace namespace, boolean managementPortDifferent) {
|
||||
StaticApplicationContext context = new StaticApplicationContext();
|
||||
if (namespace != null && !WebServerNamespace.SERVER.equals(namespace)) {
|
||||
NamedStaticWebApplicationContext parentContext = new NamedStaticWebApplicationContext(namespace);
|
||||
context.setParent(parentContext);
|
||||
if (managementPortDifferent) {
|
||||
context = new NamedStaticWebApplicationContext(namespace);
|
||||
}
|
||||
else {
|
||||
NamedStaticWebApplicationContext parentContext = new NamedStaticWebApplicationContext(namespace);
|
||||
context.setParent(parentContext);
|
||||
}
|
||||
}
|
||||
if (managementPortDifferent) {
|
||||
context.getEnvironment()
|
||||
.getPropertySources()
|
||||
.addFirst(new MapPropertySource("test", Map.of("management.server.port", 0)));
|
||||
}
|
||||
context.registerBean(WebEndpointProperties.class);
|
||||
if (pathMappedEndpoints != null) {
|
||||
|
||||
+37
-2
@@ -19,6 +19,7 @@ package org.springframework.boot.actuate.autoconfigure.security.servlet;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.assertj.core.api.AssertDelegateTarget;
|
||||
@@ -36,6 +37,7 @@ import org.springframework.boot.actuate.endpoint.web.PathMappedEndpoints;
|
||||
import org.springframework.boot.actuate.endpoint.web.WebServerNamespace;
|
||||
import org.springframework.boot.web.context.WebServerApplicationContext;
|
||||
import org.springframework.boot.web.server.WebServer;
|
||||
import org.springframework.core.env.MapPropertySource;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.mock.web.MockHttpServletRequest;
|
||||
import org.springframework.mock.web.MockServletContext;
|
||||
@@ -91,6 +93,15 @@ class EndpointRequestTests {
|
||||
assertMatcher.matches("/bar");
|
||||
}
|
||||
|
||||
@Test
|
||||
void toAnyEndpointWhenBasePathIsEmptyAndManagementPortDifferentShouldMatchLinks() {
|
||||
RequestMatcher matcher = EndpointRequest.toAnyEndpoint();
|
||||
RequestMatcherAssert assertMatcher = assertMatcher(matcher, mockPathMappedEndpoints(""), null,
|
||||
WebServerNamespace.MANAGEMENT, true);
|
||||
assertMatcher.matches("/");
|
||||
assertMatcher.matches("/foo");
|
||||
}
|
||||
|
||||
@Test
|
||||
void toAnyEndpointShouldNotMatchOtherPath() {
|
||||
RequestMatcher matcher = EndpointRequest.toAnyEndpoint();
|
||||
@@ -150,6 +161,15 @@ class EndpointRequestTests {
|
||||
assertMatcher.doesNotMatch("/");
|
||||
}
|
||||
|
||||
@Test
|
||||
void toLinksWhenBasePathEmptyAndManagementPortDifferentShouldMatchRoot() {
|
||||
RequestMatcher matcher = EndpointRequest.toLinks();
|
||||
RequestMatcherAssert assertMatcher = assertMatcher(matcher, mockPathMappedEndpoints(""), null,
|
||||
WebServerNamespace.MANAGEMENT, true);
|
||||
assertMatcher.matches("/");
|
||||
assertMatcher.doesNotMatch("/foo");
|
||||
}
|
||||
|
||||
@Test
|
||||
void excludeByClassShouldNotMatchExcluded() {
|
||||
RequestMatcher matcher = EndpointRequest.toAnyEndpoint().excluding(FooEndpoint.class, BazServletEndpoint.class);
|
||||
@@ -350,10 +370,25 @@ class EndpointRequestTests {
|
||||
|
||||
private RequestMatcherAssert assertMatcher(RequestMatcher matcher, PathMappedEndpoints pathMappedEndpoints,
|
||||
RequestMatcherProvider matcherProvider, WebServerNamespace namespace) {
|
||||
return assertMatcher(matcher, pathMappedEndpoints, matcherProvider, namespace, false);
|
||||
}
|
||||
|
||||
private RequestMatcherAssert assertMatcher(RequestMatcher matcher, PathMappedEndpoints pathMappedEndpoints,
|
||||
RequestMatcherProvider matcherProvider, WebServerNamespace namespace, boolean managementPortDifferent) {
|
||||
StaticWebApplicationContext context = new StaticWebApplicationContext();
|
||||
if (namespace != null && !WebServerNamespace.SERVER.equals(namespace)) {
|
||||
NamedStaticWebApplicationContext parentContext = new NamedStaticWebApplicationContext(namespace);
|
||||
context.setParent(parentContext);
|
||||
if (managementPortDifferent) {
|
||||
context = new NamedStaticWebApplicationContext(namespace);
|
||||
}
|
||||
else {
|
||||
NamedStaticWebApplicationContext parentContext = new NamedStaticWebApplicationContext(namespace);
|
||||
context.setParent(parentContext);
|
||||
}
|
||||
}
|
||||
if (managementPortDifferent) {
|
||||
context.getEnvironment()
|
||||
.getPropertySources()
|
||||
.addFirst(new MapPropertySource("test", Map.of("management.server.port", 0)));
|
||||
}
|
||||
context.registerBean(WebEndpointProperties.class);
|
||||
if (pathMappedEndpoints != null) {
|
||||
|
||||
Reference in New Issue
Block a user