Skip to content

Commit 155cfb1

Browse files
committed
Fix boot curies href when server has custom servlet path
Previously, the servlet path was being applied twice. Once by the code that sets up the DefaultCurieProvider and once by the provider itself which uses ServletUriComponentBuilder's fromCurrentServletMapping() to build the application URI. This commit removes the duplicate logic when creating the DefaultCurieProvider. Closes gh-6585
1 parent 5afd610 commit 155cfb1

File tree

3 files changed

+150
-11
lines changed

3 files changed

+150
-11
lines changed

spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcAutoConfiguration.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ private void createChildManagementContext() {
182182
childContext.setParent(this.applicationContext);
183183
childContext.setNamespace("management");
184184
childContext.setId(this.applicationContext.getId() + ":management");
185+
childContext.setClassLoader(this.applicationContext.getClassLoader());
185186
childContext.register(EndpointWebMvcChildContextConfiguration.class,
186187
PropertyPlaceholderAutoConfiguration.class,
187188
EmbeddedServletContainerAutoConfiguration.class,

spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcHypermediaManagementContextConfiguration.java

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -126,20 +126,9 @@ public DefaultCurieProvider curieProvider(ServerProperties server,
126126
ManagementServerProperties management, DocsMvcEndpoint endpoint) {
127127
String path = management.getContextPath() + endpoint.getPath()
128128
+ "/#spring_boot_actuator__{rel}";
129-
if (serverAndManagementPortsAreTheSame(server, management)) {
130-
path = server.getPath(path);
131-
}
132129
return new DefaultCurieProvider("boot", new UriTemplate(path));
133130
}
134131

135-
private boolean serverAndManagementPortsAreTheSame(ServerProperties server,
136-
ManagementServerProperties management) {
137-
if (server.getPort() == null) {
138-
return management.getPort() == null;
139-
}
140-
return server.getPort().equals(management.getPort()) && management.getPort() != 0;
141-
}
142-
143132
@Configuration
144133
static class DocsMvcEndpointConfiguration {
145134

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
/*
2+
* Copyright 2012-2016 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.actuate.autoconfigure;
18+
19+
import java.net.URL;
20+
21+
import com.jayway.jsonpath.JsonPath;
22+
import net.minidev.json.JSONArray;
23+
import org.junit.After;
24+
import org.junit.Test;
25+
26+
import org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext;
27+
import org.springframework.boot.context.embedded.ServerPortInfoApplicationContextInitializer;
28+
import org.springframework.boot.test.util.EnvironmentTestUtils;
29+
import org.springframework.boot.test.web.client.TestRestTemplate;
30+
import org.springframework.context.annotation.Configuration;
31+
import org.springframework.http.ResponseEntity;
32+
33+
import static org.assertj.core.api.Assertions.assertThat;
34+
35+
/**
36+
* Integration tests for the href of the actuator's curies link
37+
*
38+
* @author Andy Wilkinson
39+
*/
40+
public class BootCuriesHrefIntegrationTests {
41+
42+
private AnnotationConfigEmbeddedWebApplicationContext context;
43+
44+
@After
45+
public void closeContext() {
46+
this.context.close();
47+
}
48+
49+
@Test
50+
public void basicCuriesHref() {
51+
int port = load("endpoints.docs.curies.enabled:true", "server.port:0");
52+
assertThat(getCurieHref("http://localhost:" + port + "/actuator")).isEqualTo(
53+
"http://localhost:" + port + "/docs/#spring_boot_actuator__{rel}");
54+
}
55+
56+
@Test
57+
public void curiesHrefWithCustomContextPath() {
58+
int port = load("endpoints.docs.curies.enabled:true", "server.port:0",
59+
"server.context-path:/context");
60+
assertThat(getCurieHref("http://localhost:" + port + "/context/actuator"))
61+
.isEqualTo("http://localhost:" + port
62+
+ "/context/docs/#spring_boot_actuator__{rel}");
63+
}
64+
65+
@Test
66+
public void curiesHrefWithCustomServletPath() {
67+
int port = load("endpoints.docs.curies.enabled:true", "server.port:0",
68+
"server.servlet-path:/servlet");
69+
assertThat(getCurieHref("http://localhost:" + port + "/servlet/actuator"))
70+
.isEqualTo("http://localhost:" + port
71+
+ "/servlet/docs/#spring_boot_actuator__{rel}");
72+
}
73+
74+
@Test
75+
public void curiesHrefWithCustomServletAndContextPaths() {
76+
int port = load("endpoints.docs.curies.enabled:true", "server.port:0",
77+
"server.context-path:/context", "server.servlet-path:/servlet");
78+
assertThat(getCurieHref("http://localhost:" + port + "/context/servlet/actuator"))
79+
.isEqualTo("http://localhost:" + port
80+
+ "/context/servlet/docs/#spring_boot_actuator__{rel}");
81+
}
82+
83+
@Test
84+
public void curiesHrefWithCustomServletContextAndManagementContextPaths() {
85+
int port = load("endpoints.docs.curies.enabled:true", "server.port:0",
86+
"server.context-path:/context", "server.servlet-path:/servlet",
87+
"management.context-path:/management");
88+
assertThat(getCurieHref("http://localhost:" + port
89+
+ "/context/servlet/management/")).isEqualTo("http://localhost:" + port
90+
+ "/context/servlet/management/docs/#spring_boot_actuator__{rel}");
91+
}
92+
93+
@Test
94+
public void serverPathsAreIgnoredWithSeparateManagementPort() {
95+
int port = load("endpoints.docs.curies.enabled:true", "server.port:0",
96+
"server.context-path:/context", "server.servlet-path:/servlet",
97+
"management.port:0");
98+
assertThat(getCurieHref("http://localhost:" + port + "/actuator/")).isEqualTo(
99+
"http://localhost:" + port + "/docs/#spring_boot_actuator__{rel}");
100+
}
101+
102+
@Test
103+
public void managementContextPathWithSeparateManagementPort() {
104+
int port = load("endpoints.docs.curies.enabled:true",
105+
"management.context-path:/management", "server.port:0",
106+
"management.port:0");
107+
assertThat(getCurieHref("http://localhost:" + port + "/management/"))
108+
.isEqualTo("http://localhost:" + port
109+
+ "/management/docs/#spring_boot_actuator__{rel}");
110+
}
111+
112+
private int load(String... properties) {
113+
this.context = new AnnotationConfigEmbeddedWebApplicationContext();
114+
this.context.setClassLoader(new ClassLoader(getClass().getClassLoader()) {
115+
116+
@Override
117+
public URL getResource(String name) {
118+
if ("META-INF/resources/spring-boot-actuator/docs/index.html"
119+
.equals(name)) {
120+
return super.getResource("actuator-docs-index.html");
121+
}
122+
return super.getResource(name);
123+
}
124+
125+
});
126+
EnvironmentTestUtils.addEnvironment(this.context, properties);
127+
this.context.register(TestConfiguration.class);
128+
new ServerPortInfoApplicationContextInitializer().initialize(this.context);
129+
this.context.refresh();
130+
return Integer.parseInt(
131+
this.context.getEnvironment().getProperty("local.management.port"));
132+
}
133+
134+
private String getCurieHref(String uri) {
135+
ResponseEntity<String> response = new TestRestTemplate().getForEntity(uri,
136+
String.class);
137+
JSONArray bootCuriesHrefs = JsonPath.parse(response.getBody())
138+
.read("_links.curies[?(@.name == 'boot')].href");
139+
assertThat(bootCuriesHrefs).hasSize(1);
140+
return (String) bootCuriesHrefs.get(0);
141+
}
142+
143+
@Configuration
144+
@MinimalActuatorHypermediaApplication
145+
static class TestConfiguration {
146+
147+
}
148+
149+
}

0 commit comments

Comments
 (0)