diff --git a/spring-web/src/main/java/org/springframework/web/util/UriComponents.java b/spring-web/src/main/java/org/springframework/web/util/UriComponents.java index fcaff34da4..b9d2c60767 100644 --- a/spring-web/src/main/java/org/springframework/web/util/UriComponents.java +++ b/spring-web/src/main/java/org/springframework/web/util/UriComponents.java @@ -219,6 +219,9 @@ public abstract class UriComponents implements Serializable { if (source.indexOf('{') == -1) { return source; } + if (source.indexOf(':') != -1) { + source = sanitizeSource(source); + } Matcher matcher = NAMES_PATTERN.matcher(source); StringBuffer sb = new StringBuffer(); while (matcher.find()) { @@ -236,6 +239,27 @@ public abstract class UriComponents implements Serializable { return sb.toString(); } + /** + * Remove nested "{}" such as in URI vars with regular expressions. + */ + private static String sanitizeSource(String source) { + int level = 0; + StringBuilder sb = new StringBuilder(); + for (char c : source.toCharArray()) { + if (c == '{') { + level++; + } + if (c == '}') { + level--; + } + if (level > 1 || (level == 1 && c == '}')) { + continue; + } + sb.append(c); + } + return sb.toString(); + } + private static String getVariableName(String match) { int colonIdx = match.indexOf(':'); return (colonIdx != -1 ? match.substring(0, colonIdx) : match); diff --git a/spring-web/src/test/java/org/springframework/web/util/UriComponentsTests.java b/spring-web/src/test/java/org/springframework/web/util/UriComponentsTests.java index dcaa62b1e8..7a43337cc5 100644 --- a/spring-web/src/test/java/org/springframework/web/util/UriComponentsTests.java +++ b/spring-web/src/test/java/org/springframework/web/util/UriComponentsTests.java @@ -16,10 +16,6 @@ package org.springframework.web.util; -import static org.hamcrest.Matchers.*; -import static org.junit.Assert.*; -import static org.springframework.web.util.UriComponentsBuilder.*; - import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; @@ -27,9 +23,17 @@ import java.io.ObjectOutputStream; import java.net.URI; import java.net.URISyntaxException; import java.util.Arrays; +import java.util.Collections; import org.junit.Test; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.not; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; +import static org.springframework.web.util.UriComponentsBuilder.fromUriString; + /** * @author Arjen Poutsma * @author Phillip Webb @@ -82,6 +86,16 @@ public class UriComponentsTests { assertEquals("http://example.com/1 2 3 4", uriComponents.toUriString()); } + // SPR-13311 + + @Test + public void expandWithRegexVar() { + String template = "/myurl/{name:[a-z]{1,5}}/show"; + UriComponents uriComponents = UriComponentsBuilder.fromUriString(template).build(); + uriComponents = uriComponents.expand(Collections.singletonMap("name", "test")); + assertEquals("/myurl/test/show", uriComponents.getPath()); + } + // SPR-12123 @Test