From 69b60f6d8c84d66dc42fe75711d6eedbc9df0bba Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Mon, 18 Jan 2016 14:32:01 +0000 Subject: [PATCH] =?UTF-8?q?Remove=20HalJsonMvcEndpoint=E2=80=99s=20redirec?= =?UTF-8?q?t=20and=20add=20links=20to=20both=20paths=20instead?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously, HalJsonMvcEndpoint used a redirect to go from path/ to path. When the actuator’s configured to use a custom context path this redirect was leading to an infinite redirect loop. This commit removes the redirect in favour of updating the controller advice to apply the links to requests for path and path/. Closes gh-4853 --- ...HypermediaManagementContextConfiguration.java | 10 +++++++--- .../actuate/endpoint/mvc/HalJsonMvcEndpoint.java | 7 +------ ...intManagementContextPathIntegrationTests.java | 8 +++----- ...ndpointServerContextPathIntegrationTests.java | 14 +++++++++++++- ...serMvcEndpointServerPortIntegrationTests.java | 16 +++++++++++++++- ...rowserMvcEndpointVanillaIntegrationTests.java | 9 ++++++++- 6 files changed, 47 insertions(+), 17 deletions(-) diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcHypermediaManagementContextConfiguration.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcHypermediaManagementContextConfiguration.java index 1482d0220a7..94e0bff791f 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcHypermediaManagementContextConfiguration.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/autoconfigure/EndpointWebMvcHypermediaManagementContextConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2015 the original author or authors. + * Copyright 2012-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -196,8 +196,12 @@ public class EndpointWebMvcHypermediaManagementContextConfiguration { } private boolean isActuatorEndpointPath(String path) { - return this.halJsonMvcEndpoint != null && (this.management.getContextPath() - + this.halJsonMvcEndpoint.getPath()).equals(path); + if (this.halJsonMvcEndpoint != null) { + String toMatch = this.management.getContextPath() + + this.halJsonMvcEndpoint.getPath(); + return toMatch.equals(path) || (toMatch + "/").equals(path); + } + return false; } } diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/HalJsonMvcEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/HalJsonMvcEndpoint.java index cb165235803..c0c32516adc 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/HalJsonMvcEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/HalJsonMvcEndpoint.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2015 the original author or authors. + * Copyright 2012-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -87,11 +87,6 @@ public class HalJsonMvcEndpoint extends WebMvcConfigurerAdapter return new ResourceSupport(); } - @RequestMapping(path = "/", produces = MediaType.APPLICATION_JSON_VALUE) - public String forward() { - return "redirect:" + this.managementServletContext.getContextPath() + this.path; - } - public void setPath(String path) { this.path = path; } diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/HalBrowserMvcEndpointManagementContextPathIntegrationTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/HalBrowserMvcEndpointManagementContextPathIntegrationTests.java index 0afafcb4480..9b65cdd077c 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/HalBrowserMvcEndpointManagementContextPathIntegrationTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/HalBrowserMvcEndpointManagementContextPathIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2015 the original author or authors. + * Copyright 2012-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -39,7 +39,6 @@ import org.springframework.web.context.WebApplicationContext; import static org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.forwardedUrl; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -77,10 +76,9 @@ public class HalBrowserMvcEndpointManagementContextPathIntegrationTests { } @Test - public void redirectJson() throws Exception { + public void actuatorHomeWithTrailingSlashJson() throws Exception { this.mockMvc.perform(get("/admin/").accept(MediaType.APPLICATION_JSON)) - .andExpect(status().isFound()) - .andExpect(header().string("location", "/admin")); + .andExpect(status().isOk()).andExpect(jsonPath("$._links").exists()); } @Test diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/HalBrowserMvcEndpointServerContextPathIntegrationTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/HalBrowserMvcEndpointServerContextPathIntegrationTests.java index 8ad3a60c7d3..855dc417572 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/HalBrowserMvcEndpointServerContextPathIntegrationTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/HalBrowserMvcEndpointServerContextPathIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2015 the original author or authors. + * Copyright 2012-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -97,6 +97,18 @@ public class HalBrowserMvcEndpointServerContextPathIntegrationTests { entity.getBody().contains("\"_links\":")); } + @Test + public void actuatorLinksWithTrailingSlash() throws Exception { + HttpHeaders headers = new HttpHeaders(); + headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON)); + ResponseEntity entity = new TestRestTemplate().exchange( + "http://localhost:" + this.port + "/spring/actuator/", HttpMethod.GET, + new HttpEntity(null, headers), String.class); + assertEquals(HttpStatus.OK, entity.getStatusCode()); + assertTrue("Wrong body: " + entity.getBody(), + entity.getBody().contains("\"_links\":")); + } + @MinimalActuatorHypermediaApplication @RestController public static class SpringBootHypermediaApplication { diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/HalBrowserMvcEndpointServerPortIntegrationTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/HalBrowserMvcEndpointServerPortIntegrationTests.java index 495cfc21927..6f9ca98e3a2 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/HalBrowserMvcEndpointServerPortIntegrationTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/HalBrowserMvcEndpointServerPortIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2015 the original author or authors. + * Copyright 2012-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -75,6 +75,20 @@ public class HalBrowserMvcEndpointServerPortIntegrationTests { entity.getBody().contains(":" + this.port)); } + @Test + public void linksWithTrailingSlash() throws Exception { + HttpHeaders headers = new HttpHeaders(); + headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON)); + ResponseEntity entity = new TestRestTemplate().exchange( + "http://localhost:" + this.port + "/actuator/", HttpMethod.GET, + new HttpEntity(null, headers), String.class); + assertEquals(HttpStatus.OK, entity.getStatusCode()); + assertTrue("Wrong body: " + entity.getBody(), + entity.getBody().contains("\"_links\":")); + assertTrue("Wrong body: " + entity.getBody(), + entity.getBody().contains(":" + this.port)); + } + @Test public void browser() throws Exception { HttpHeaders headers = new HttpHeaders(); diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/HalBrowserMvcEndpointVanillaIntegrationTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/HalBrowserMvcEndpointVanillaIntegrationTests.java index f9f0c9c4a5b..681f959b2f4 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/HalBrowserMvcEndpointVanillaIntegrationTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/HalBrowserMvcEndpointVanillaIntegrationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2015 the original author or authors. + * Copyright 2012-2016 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -78,6 +78,13 @@ public class HalBrowserMvcEndpointVanillaIntegrationTests { .andExpect(header().doesNotExist("cache-control")); } + @Test + public void linksWithTrailingSlash() throws Exception { + this.mockMvc.perform(get("/actuator/").accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()).andExpect(jsonPath("$._links").exists()) + .andExpect(header().doesNotExist("cache-control")); + } + @Test public void browser() throws Exception { MvcResult response = this.mockMvc