Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simplify options for strict encoding of URI variable when using UriComponentsBuilder [SPR-14970] #19536

Closed
spring-projects-issues opened this issue Dec 1, 2016 · 8 comments
Assignees
Labels
in: web Issues in web modules (web, webmvc, webflux, websocket) type: enhancement A general enhancement
Milestone

Comments

@spring-projects-issues
Copy link
Collaborator

spring-projects-issues commented Dec 1, 2016

Andrew Garland opened SPR-14970 and commented

Because of past (html4) W3C recommendation, some web servers treat semi-colon as a separator of query parameters in addition to &.
https://www.w3.org/TR/1999/REC-html401-19991224/appendix/notes.html#h-B.2.2

When interacting with such servers, the HierarchicalUriComponents.encodeQueryParams (and by extension .encode) will not produce a usable URL.

For example, it will generate https://192.168.46.168/query/?name_eq=C;D

but the server will fail to find an object named 'C;D'

If the URL generated were https://192.168.46.168/query/?name_eq=C%3BD

the server will return the correct object.

I don't see the harm in UTF-8 percent encoding the semi-colon in query parameters in all cases. If there is such a downside, then there at least needs to be a way to customize the behavior in order to properly interact with such servers.

A more ambitious change would be to UTF-8 Percent encode all of the characters noted as part of the userinfo encode set in the html5 URL spec https://url.spec.whatwg.org FWIW, I could not find any html5 recommendations about using the semi-colon similar to the one referenced above.


Affects: 4.2.6

Referenced from: commits bb3b1f2

@spring-projects-issues
Copy link
Collaborator Author

spring-projects-issues commented Dec 1, 2016

Andrew Garland commented

I left importance as minor but this issue forces me to manually convert ';' to %3B in query parameters before passing to a rest templates for execution, which is ugly.

@spring-projects-issues
Copy link
Collaborator Author

spring-projects-issues commented Dec 1, 2016

Andrew Garland commented

FWIW, java.net.URI does not percent encode semi-colon in query parameters either :(

@spring-projects-issues
Copy link
Collaborator Author

spring-projects-issues commented Jan 4, 2017

Rossen Stoyanchev commented

The character rules in HierarchicalUriCompoments.Type are driven by the URI spec and follow the syntax from appendix A (this is also mentioned in the Javadoc by the way). As per the spec, the query can contain pchar which includes sub-delimiters and that includes ";". In short it is a legal character in query parameters.

The RestTemplate has a UriTemplateHandler strategy whose default implementation offers a "strictEncoding" property. You can do something similar applying UriUtils.encode(value, "UTF-8") to each value and also using the build method with the encoded flag to prevent further encoding (for example when toUri() is called and also if encode() is called explicitly):

public static void main(String[] args) {
    UriComponentsBuilder
            .fromUriString("https://192.168.46.168/query/?name_eq={value}")
            .build(true)
            .expand(encode("C;D"))
            .toUri();
}

private static Object[] encode(String... values) {
    // ...
}

private static Map<String, ?> encode(Map<String, ?> values) {
    // ...
}

@spring-projects-issues
Copy link
Collaborator Author

spring-projects-issues commented Jan 4, 2017

Rossen Stoyanchev commented

We could also expose this as an additional build method on UriComponentsBuilder that can apply the same strict encoding of URI variable values (as the DefaultUriTemplateHandler does) and then build with encoded=true and expand:

public Map<String, ?> encodeBuildAndExpand(Map<String, ?> uriVariables) {
    Map<String, ?> encoded = encode(uriVariables);  // apply "strict" encoding
    return build(true).expand(encoded);
}

That would make sense in terms of aligning what's possible indirectly when using the RestTemplate vs direct use of UriComponentsBuilder.

Oliver Drotbohm I believe you were looking for something similar recently?

@spring-projects-issues
Copy link
Collaborator Author

spring-projects-issues commented Jan 5, 2017

Oliver Drotbohm commented

In our case we only wanted to encode the values actually provided, but keep other template variables intact so that the remaining curly braces and ampersands etc. stay intact.

@spring-projects-issues
Copy link
Collaborator Author

spring-projects-issues commented Jan 5, 2017

Rossen Stoyanchev commented

Good, that's exactly what the proposed method would do.

@spring-projects-issues
Copy link
Collaborator Author

spring-projects-issues commented Jan 19, 2017

Rossen Stoyanchev commented

Modified title (was: "HierarchicalUriComponents.Type.QUERY_PARAM should return false for isAllowed(';')").

@spring-projects-issues
Copy link
Collaborator Author

spring-projects-issues commented Jan 19, 2017

Rossen Stoyanchev commented

I've created methods in UriUtils for "strict" encoding URI variables. That can be used as follows:

Map<String, ?> encodedVars = UriUtils.encodeUriVariables(vars);
URI uri = uriComponentsBuilder.build(true).expand(encodedVars).toUri();

@spring-projects-issues spring-projects-issues added type: enhancement A general enhancement in: web Issues in web modules (web, webmvc, webflux, websocket) labels Jan 11, 2019
@spring-projects-issues spring-projects-issues added this to the 5.0 M5 milestone Jan 11, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: web Issues in web modules (web, webmvc, webflux, websocket) type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

2 participants