Skip to content

Support RFC 6570 style URI template encoding [SPR-12942] #17535

Closed
@spring-projects-issues

Description

@spring-projects-issues

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:

Referenced from: commits ca410fe

Metadata

Metadata

Assignees

Labels

in: webIssues in web modules (web, webmvc, webflux, websocket)status: declinedA suggestion or change that we don't feel we should currently applytype: taskA general task

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions