Skip to content

UriTemplate handles encoded variables improperly on expand call #593

Closed
@billyyarosh

Description

@billyyarosh

When testing the UriTemplate, we ran into several issues with encoding. The URI template, when given a path like /foo%20bar will return /foo%252520bar on a call to expand. It looks like both the hateoas UriTemplate and the spring UriTemplate are not handling ecoded URLs. Also if you provide a URL with a character needing encoding, you get the % sign escaped only once.

Here is a spock test to shows the errors. The last three tests will fail due to the issues.

@Unroll("template expand with params '#params' and uri '#uri' results in '#expectedUri ")
    def "template expands with parameter map"() {
        when:
        UriTemplate template = new UriTemplate(uri)
        String expandedUri = template.expand(params)

        then:
        expandedUri == expectedUri

        where:
        uri                             | params                      | expectedUri
        '/foo/bar{?x}'                  | ['x': 1]                    | '/foo/bar?x=1'
        '/foo/bar{?x,y}'                | ['x': 1, 'y': "2"]          | '/foo/bar?x=1&y=2'
        '/foo/bar{?x}{&y}'              | ['x': 1, 'y': "2"]          | '/foo/bar?x=1&y=2'
        '/foo/bar?x=1{&y}'              | ['y': 2]                    | '/foo/bar?x=1&y=2'
        '/foo/bar?x=1{&y,z}'            | ['y': 2, 'z': 3L]           | '/foo/bar?x=1&y=2&z=3'
        '/foo{/x}'                      | ['x': 1]                    | '/foo/1'
        '/foo{/x,y}'                    | ['x': 1, 'y': "2"]          | '/foo/1/2'
        '/foo{/x}{/y}'                  | ['x': 1, 'y': "2"]          | '/foo/1/2'
        '/foo{/x}{/y}{?z}'              | ['x': 1, 'y': "2", 'z': 3L] | '/foo/1/2?z=3'
        '/foo/{x}'                      | ['x': 1]                    | '/foo/1'
        '/foo/{x}/bar'                  | ['x': 1]                    | '/foo/1/bar'
        '/services/foo/{x}/bar/{y}/gaz' | ['x': 1, 'y': "2"]          | '/services/foo/1/bar/2/gaz'
        '/foo/{x}/bar/{y}/bar{?z}'      | ['x': 1, 'y': "2", 'z': 3L] | '/foo/1/bar/2/bar?z=3'
        '/foo/{x}/bar/{y}/bar{?z}'      | ['x': 1, 'y': "2"]          | '/foo/1/bar/2/bar'
        '/foo/bar{?x,y,z}'              | ['x': 1]                    | '/foo/bar?x=1'
        '/foo/bar{?x,y,z}'              | ['x': 1, 'y': "2"]          | '/foo/bar?x=1&y=2'
        '/foo/bar{?x,y,z}'              | ['x': 1, 'z': 3L]           | '/foo/bar?x=1&z=3'
        '/foo/{x}/bar{/y}{?z}'          | ['x': 1, 'y': "2", 'z': 3L] | '/foo/1/bar/2?z=3'
        '/foo/{x}/bar{/y}{?z}'          | ['x': 1, 'z': 3L]           | '/foo/1/bar?z=3'
        '/foo/{x}/bar{?y}{#z}'          | ['x': 1, 'y': "2"]          | '/foo/1/bar?y=2'
        '/foo/{x}/bar{?y}{#z}'          | ['x': 1, 'y': "2", 'z': 3L] | '/foo/1/bar?y=2#3'
        '/foo/{x}/bar{?y}{#z}'          | ['x': 1, 'z': 3L]           | '/foo/1/bar#3'
        '/foo/b%20ar{?x}'               | ['x': 1]                    | '/foo/b%20ar?x=1'
        '/foo/b"ar{?x}'                 | ['x': 1]                    | '/foo/b%22ar?x=1'
        '/foo/b%22ar{?x}'               | ['x': 1]                    | '/foo/b%22ar?x=1'
    }

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions