Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,13 @@ && getServerNamespace(applicationContext) == null
return (applicationContext != null) ? applicationContext.getParent() : null;
}

protected final @Nullable 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)
Expand Down Expand Up @@ -334,7 +341,8 @@ protected ServerWebExchangeMatcher createDelegate(PathMappedEndpoints endpoints)
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()) {
Expand Down Expand Up @@ -370,10 +378,17 @@ private LinksServerWebExchangeMatcher() {

@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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -224,13 +224,27 @@ protected final List<RequestMatcher> getDelegateMatchers(RequestMatcherFactory r
}

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 @Nullable 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 context.getBean(RequestMatcherProvider.class);
Expand Down Expand Up @@ -341,8 +355,9 @@ protected RequestMatcher createDelegate(WebApplicationContext context,
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;
Expand Down Expand Up @@ -375,10 +390,10 @@ public static final class LinksRequestMatcher extends AbstractRequestMatcher {
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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

import org.assertj.core.api.AssertDelegateTarget;
import org.jspecify.annotations.Nullable;
Expand All @@ -36,6 +37,7 @@
import org.springframework.boot.web.server.WebServer;
import org.springframework.boot.web.server.context.WebServerApplicationContext;
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;
Expand Down Expand Up @@ -93,6 +95,15 @@ void toAnyEndpointWhenBasePathIsEmptyShouldNotMatchLinks() {
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();
Expand Down Expand Up @@ -145,6 +156,15 @@ void toLinksWhenBasePathEmptyShouldNotMatch() {
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()
Expand Down Expand Up @@ -327,10 +347,26 @@ private RequestMatcherAssert assertMatcher(ServerWebExchangeMatcher matcher,

private RequestMatcherAssert assertMatcher(ServerWebExchangeMatcher matcher,
@Nullable PathMappedEndpoints pathMappedEndpoints, @Nullable WebServerNamespace namespace) {
return assertMatcher(matcher, pathMappedEndpoints, namespace, false);
}

private RequestMatcherAssert assertMatcher(ServerWebExchangeMatcher matcher,
@Nullable PathMappedEndpoints pathMappedEndpoints, @Nullable 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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
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;
Expand All @@ -37,6 +38,7 @@
import org.springframework.boot.security.autoconfigure.actuate.web.servlet.EndpointRequest.EndpointRequestMatcher;
import org.springframework.boot.web.server.WebServer;
import org.springframework.boot.web.server.context.WebServerApplicationContext;
import org.springframework.core.env.MapPropertySource;
import org.springframework.http.HttpMethod;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockServletContext;
Expand Down Expand Up @@ -92,6 +94,15 @@ void toAnyEndpointWhenBasePathIsEmptyShouldNotMatchLinks() {
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();
Expand Down Expand Up @@ -151,6 +162,15 @@ void toLinksWhenBasePathEmptyShouldNotMatch() {
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);
Expand Down Expand Up @@ -353,10 +373,26 @@ private RequestMatcherAssert assertMatcher(RequestMatcher matcher,
private RequestMatcherAssert assertMatcher(RequestMatcher matcher,
@Nullable PathMappedEndpoints pathMappedEndpoints, @Nullable RequestMatcherProvider matcherProvider,
@Nullable WebServerNamespace namespace) {
return assertMatcher(matcher, pathMappedEndpoints, matcherProvider, namespace, false);
}

private RequestMatcherAssert assertMatcher(RequestMatcher matcher,
@Nullable PathMappedEndpoints pathMappedEndpoints, @Nullable RequestMatcherProvider matcherProvider,
@Nullable 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) {
Expand Down