diff --git a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/resource/ResourceController.java b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/resource/ResourceController.java index fdd5c948..409adc50 100644 --- a/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/resource/ResourceController.java +++ b/spring-cloud-config-server/src/main/java/org/springframework/cloud/config/server/resource/ResourceController.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 the original author or authors. + * Copyright 2015-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. @@ -20,11 +20,14 @@ import java.io.IOException; import java.io.InputStream; import java.nio.charset.Charset; +import javax.servlet.http.HttpServletRequest; + import org.springframework.cloud.config.server.environment.EnvironmentRepository; import org.springframework.core.env.StandardEnvironment; import org.springframework.core.io.Resource; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; +import org.springframework.util.AntPathMatcher; import org.springframework.util.StreamUtils; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.PathVariable; @@ -32,6 +35,7 @@ import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.servlet.HandlerMapping; import static org.springframework.cloud.config.server.support.EnvironmentPropertySource.prepareEnvironment; import static org.springframework.cloud.config.server.support.EnvironmentPropertySource.resolvePlaceholders; @@ -61,10 +65,25 @@ public class ResourceController { this.environmentRepository = environmentRepository; } - @RequestMapping("/{name}/{profile}/{label}/{path:.*}") - public synchronized String resolve(@PathVariable String name, + @RequestMapping("/{name}/{profile}/{label}/**") + public String resolve(@PathVariable String name, @PathVariable String profile, @PathVariable String label, - @PathVariable String path) throws IOException { + HttpServletRequest request) throws IOException { + String pattern = (String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE); + if (pattern == null) { + throw new IllegalStateException("Required request attribute '" + + HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE + "' is not set"); + } + String path = (String) request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE); + if (path == null) { + throw new IllegalStateException("Required request attribute '" + + HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE + "' is not set"); + } + path = new AntPathMatcher().extractPathWithinPattern(pattern, path); + return resolve(name, profile, label, path); + } + + synchronized String resolve(String name, String profile, String label, String path) throws IOException { if (label != null && label.contains("(_)")) { // "(_)" is uncommon in a git branch name, but "/" cannot be matched // by Spring MVC @@ -81,10 +100,25 @@ public class ResourceController { } } - @RequestMapping(value = "/{name}/{profile}/{label}/{path:.*}", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE) + @RequestMapping(value = "/{name}/{profile}/{label}/**", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE) public synchronized byte[] binary(@PathVariable String name, @PathVariable String profile, @PathVariable String label, - @PathVariable String path) throws IOException { + HttpServletRequest request) throws IOException { + String pattern = (String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE); + if (pattern == null) { + throw new IllegalStateException("Required request attribute '" + + HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE + "' is not set"); + } + String path = (String) request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE); + if (path == null) { + throw new IllegalStateException("Required request attribute '" + + HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE + "' is not set"); + } + path = new AntPathMatcher().extractPathWithinPattern(pattern, path); + return binary(name, profile, label, path); + } + + synchronized byte[] binary(String name, String profile, String label, String path) throws IOException { if (label != null && label.contains("(_)")) { // "(_)" is uncommon in a git branch name, but "/" cannot be matched // by Spring MVC diff --git a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/resource/ResourceControllerTests.java b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/resource/ResourceControllerTests.java index a5ae28fa..34c52ad9 100644 --- a/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/resource/ResourceControllerTests.java +++ b/spring-cloud-config-server/src/test/java/org/springframework/cloud/config/server/resource/ResourceControllerTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 the original author or authors. + * Copyright 2015-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. @@ -86,6 +86,13 @@ public class ResourceControllerTests { assertEquals("foo: dev_bar/spam", resource); } + @Test + public void resourceWithSlash() throws Exception { + this.environmentRepository.setSearchLocations("classpath:/test"); + String resource = this.controller.resolve("foo", "bar", "dev", "spam/foo.txt"); + assertEquals("foo: dev_bar/spam", resource); + } + @Test public void labelWithSlashForBinary() throws Exception { this.environmentRepository.setSearchLocations("classpath:/test"); @@ -93,4 +100,11 @@ public class ResourceControllerTests { assertEquals("foo: dev_bar/spam", new String(resource)); } + @Test + public void resourceWithSlashForBinary() throws Exception { + this.environmentRepository.setSearchLocations("classpath:/test"); + byte[] resource = this.controller.binary("foo", "bar", "dev", "spam/foo.txt"); + assertEquals("foo: dev_bar/spam", new String(resource)); + } + }