Skip to content

UriComponentsBuilder inconsistent encode/decode query params behavior [SPR-16002] #20551

Closed
@spring-projects-issues

Description

@spring-projects-issues

Vsevolod Kalinin opened SPR-16002 and commented

After working with that for quite some time I have a strong feeling that something is wrong with UriComponentsBuilder query params encoding/decoding. Will try to explain it step by step now + my vision to the problem (still with hope of doing something wrong/missing something :)). Will use fromHttpUrl(..) in examples, but the behavior is the same for all from*(..) methods of all *UriComponentsBuilder classes (and it hurt even more when using something like fromHttpRequest(..)).

Use cases

So, consider I want to take current request URL, modify it (add/remove query params, etc.) and eventually use it somewhere else. Again there are fromHttpUrl(..) calls below for simplicity; IRL they are fromHttpRequest(..), etc.

  1. h3. Double-encoded query params from original URL
UriComponentsBuilder ucb = UriComponentsBuilder.fromHttpUrl("http://host.com?name=Tom%26Jerry");
ucb.queryParam("album", "S&M");
ucb.toUriString(); // http://host.com?name=Tom%2526Jerry&album=S%26M

It returns http://host.com?name=Tom%2526Jerry&album=S%26M which is wrong (see double-encoded initial name param).
I was only able to solve the above with something like:

UriComponentsBuilder ucb = UriComponentsBuilder.fromHttpUrl("http://host.com?name=Tom%26Jerry");
ucb.queryParam("album", java.net.URLEncoder.encode("S&M"));
ucb.build(true).toUriString();

Now it returns the correct http://host.com?name=Tom%26Jerry&album=S%26M, but the whole thing got a bit ugly.

  1. h3. application/x-www-form-urlencoded whitespaces
    Now the request has application/x-www-form-urlencoded whitespace (converted to +) and taught by the bitter experience above we use ucb.build(true).toUriString():
UriComponentsBuilder ucb = UriComponentsBuilder.fromHttpUrl("http://host.com?name=Tom+Jerry");
ucb.queryParam("album", "S&M");
ucb.build(true).toUriString();

But it's java.lang.IllegalArgumentException now - UriComponentsBuilder doesn't like "+".

Reverting to the initial approach doesn't work either:

UriComponentsBuilder ucb = UriComponentsBuilder.fromHttpUrl("http://host.com?name=Tom+Jerry");
ucb.queryParam("album", "S&M");
ucb.toUriString();

results in http://host.com?name=Tom%2BJerry&album=S%26M - note "+" being encoded now.

The only option is to do an ugly workaround mentioned in #14805.

Probable solution

IMHO it would have been much more convenient if UriComponentsBuilder decoded query params while parsing (presumably with application/x-www-form-urlencoded support; at least when creating from a request where MIME type should be available). This way both cases above are solved + a test

final String requestHttpUrl = <any valid request URL>;
final String processedHttpUrl = UriComponentsBuilder.fromHttpUrl(requestHttpUrl).toUriString();
assertEquals(processedHttpUrl, requestHttpUrl);

will pass for any valid URL which is what I'd expect. Although backward compatibility concern won't make it happen easily...

Looking forward for help with this one :D


Affects: 4.3.11

Issue Links:

Metadata

Metadata

Assignees

Labels

in: webIssues in web modules (web, webmvc, webflux, websocket)status: duplicateA duplicate of another issue

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions