Description
daniel carter opened SPR-12942 and commented
As per RFC6570, the URI template "http://host/path/${var1}" where var1=a/b should expand to "http://host/path/a%2Fb"
actual result is "http://host/path/a/b"
Current spring behaviour, as per RFC6570, should only occur when the + operator is specified, ie "http://host/path/${+var1}"
Relevant parts of the spec:
3.2.1 Variable Expansion
The allowed set for a given expansion depends on the expression type: reserved ("+") and fragment ("#") expansions allow the set of characters in the union of ( unreserved / reserved / pct-encoded ) to be passed through without pct-encoding, whereas all other expression types allow only unreserved characters to be passed through without pct-encoding.
Section 3.2.3 shows an explicit example illustrating that / should be encoded unless the + operator is used. (base := "http://example.com/home/")
{base}index http%3A%2F%2Fexample.com%2Fhome%2Findex
{+base}index http://example.com/home/index
Spring is also falling over with it's new ${/var} support as it is failing to add the /
3.2.6
For each defined variable in the variable-list, append "/" to the result string and then perform variable expansion
Here are some test cases to further illustrate the issue, and a comparison with another RFC6570 template library. Run against 4.2.0.BUILD-SNAPSHOT
import org.hamcrest.Matchers;
import org.junit.Assert;
import org.junit.Test;
/**
* @author cartedan
*
*/
public class URLEncodingTest {
@Test
public void testDamnHandyDefaultSyntax() {
String uri = com.damnhandy.uri.template.UriTemplate.fromTemplate("http://localhost:80/path/{var1}").set("var1", "my/Id").expand();
Assert.assertThat(uri, Matchers.is("http://localhost:80/path/my%2FId"));
}
@Test
public void testDamnHandyPlusSyntax() {
String uri = com.damnhandy.uri.template.UriTemplate.fromTemplate("http://localhost:80/path/{+var1}").set("var1", "my/Id").expand();
Assert.assertThat(uri, Matchers.is("http://localhost:80/path/my/Id"));
}
@Test
public void testDamnHandySlashSyntax() {
String uri = com.damnhandy.uri.template.UriTemplate.fromTemplate("http://localhost:80/path{/var1}").set("var1", "my/Id").expand();
Assert.assertThat(uri, Matchers.is("http://localhost:80/path/my%2FId"));
}
@Test
public void testSpringDefaultSyntax() {
String uri = new org.springframework.web.util.UriTemplate("http://localhost:80/path/{var1}").expand("my/Id").toString();
// Fails, as spring does not correctly encode / in variable values
Assert.assertThat(uri, Matchers.is("http://localhost:80/path/my%2FId"));
}
@Test
public void testSpringPlusSyntax() {
String uri = new org.springframework.web.util.UriTemplate("http://localhost:80/path/{+var1}").expand("my/Id").toString();
Assert.assertThat(uri, Matchers.is("http://localhost:80/path/my/Id"));
}
@Test
public void testSpringSlashSyntax() {
String uri = new org.springframework.web.util.UriTemplate("http://localhost:80/path{/var1}").expand("my/Id").toString();
// Fails as spring does not append the slash before doing the variable substitution.
Assert.assertThat(uri, Matchers.is("http://localhost:80/path/my%2FId"));
}
}
<dependency>
<groupId>com.damnhandy</groupId>
<artifactId>handy-uri-templates</artifactId>
<version>2.0.2</version>
</dependency>
I understand the desire expressed in earlier bug reports to maintain backward compatibility. Now that RFC6570 is becoming well supported, spring 4.2 would seem a good time to switch to the RFC behaviour, while allowing a configuration parameter to switch back to springs earlier behaviour.
Affects: 4.1.6
This issue is a sub-task of #15137
Issue Links:
- Support limited subset of RFC 6570 syntax including operators "", "?", "/", "#" [SPR-14134] #18706 Support limited subset of RFC 6570 syntax including operators "", "?", "/", "#"
Referenced from: commits ca410fe