Uribuilder encoding with exclamation mark - java

I'm trying to use Uribuilder from:
javax.ws.rs.core.UriBuilder;
To update a URI. The issue is that the parameter name gets escaped when I use replaceQueryParam.
so:
UriBuilder uriBuilder = webResource.getUriBuilder().
replaceQueryParam("abcd!dcv, "wid").
replaceQueryParam("format", "json");
if there is already an existing "abcd!dcv" parameter in the Uribuilder, it will escape and add a new one. so it will become
?abcd!dcv=originalvalue&abcd%21cdv=wid
instead of
?abcd!dcv=wid
How should I get around this? Thanks!

URIBuilder is an abstract class and the implementation gets to decide which characters need special encoding and which do not. The URIBuilder we get from a WebResource is attempting to follow the guidelines of RFC 3986. On page 12, ! is listed as a sub-delimiter and this is why it is getting encoded. From my reading of the RFC, I don't think we should be using ! as part of a query parameter. For instance, Vaading uses ! to distinguish between sub-windows of the same application.
The simplest work around I can think of is to simply not use URIBuilder or use the fromURI method that takes a String as input. You can create the URI with everything except the part with the characters we don't want encoded, convert this to astring, manipulate astring to replace the query parameter and then call URIBuilder.fromURI(aString)

Related

Java - how to build an URI using a query string that is already escaped?

LATER EDIT: not same problem as the suggested answer. In my case, I need to build the URI, relying on the fact that the original query string is not modified.
I have a String (coming from a request query String) that is already correctly escaped, like param1=%2Ffolder1%2Ffolder2%2Ffolder%26name%202&param2=9481dxcv234.
The decoded value of param1 is /folder1/folder2/folder&name 2. Obviously, I cannot unescape that String (because of the & char in this value)...
I need to build an URI which has that original string as query value.
I tried using org.apache.http.client.utils.URIBuilder but could not get it to work: if I provide the original String to the URI(... constructor, the resulting URL is double-escaped, like param1=%252Ffolder1%252Ffolder2%252Ffolder%2526name%25202&param2=9481dxcv234.
Can I somehow do what I need ? To build an URI by passing the query string already escaped and leave it unchanged ?
Thanks.
I think, the simplest way is unescape it first.
Then you can work with url as usualy.
You could use org.springframework.web.util.UriComponentsBuilder:
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url);
UriComponents components = builder.build(true); //EDIT: pass true when the URI was fully encoded already.
MultiValueMap<String, String> parameters = components.getQueryParams();
parameters.get("param1") //"%2Ffolder1%2Ffolder2%2Ffolder%26name%202"
You can then URLDecode to get what you need.
Edit:
Since you appear to be using Apache HttpClient,
List<NameValuePair> params = org.apache.http.client.utils.URLEncodedUtils.parse(new URI(url), Charset.forName("UTF-8"));
params.get("param1") //"/folder1/folder2/folder&name 2"

How to URL-encode the the whole xml value of a query param using Spring's rest template?

I am working on a Spring Boot application
I need to make a request to an external service, old and ill-conceived. The request take the form of a HTTP GET (or POST) call, but the payload, an xml content, need to be passed as a query parameter. For example,
GET http://ill-service.com/plain.cgi?XML_DATA=<request attribute="attributeValue"><content contentAttribute="plain"/></request>
Of course, the value of query param XML_DATA need to be URL encoded, and normally, the RestTemplate of Spring boot work good on that, following RFC 3986 (see http://www.ietf.org/rfc/rfc3986.txt).
Except that, as allowed by this RFC, '/' and '=' character are left in the param value, giving me the following query :
GET http://ill-service.com/plain.cgi?XML_DATA=%3Crequest%20attribute=%22attributeValue%22%3E%3Ccontent%20contentAttribute=%22plain%22/%3E%3C/request%3E
In a perfect wold, this would be good, but do you remember when I said that the service I am trying to call is ill-conceived ? In another world, it needs to have the full content of XML_DATA URL-encoded. In another words, it needs the following query:
GET http://ill-service.com/plain.cgi?XML_DATA=%3Crequest%20attribute%3D%22attributeValue%22%3E%3Ccontent%20contentAttribute%3D%22plain%22%2F%3E%3C%2Frequest%3E%0A
I am quite lost on how to instruct the rest template or the UriComponentBuilder I am using to do so. Any help would be greatly appreciated
Probably u can use spring's UriUtils class
Use java.net.URLEncoder to encode your XML payload first and then append the encoded payload.
Following the suggestion of Vasif, and some information about UriComponentBuilder I found the following solutions :
String xmlContent = "<request attribute="attributeValue"><content contentAttribute="plain"/></request>";
URI uri = UriComponentsBuilder.fromHttpUrl("http://ill-service.com/plain.cgi")
//This part set the query param as a full encoded value, not as query value encoded
.queryParam("XML_DATA", UriUtils.encode(xmlContent, "UTF-8"))
//The build(true) indicate to the builder that the Uri is already encoded
.build(true).toUri();
String responseStr = restTemplate.getForObject(uri ,String.class)

Stuck on ControllerLinkBuilder

I am currently trying to encode part of the URL but not all of it
Here is a sample of it:
http://localhost:8080/resourceSearch?type=http%3A%2F%2Fexample.com%2FSSTG.owl%25252523Project&searchTerms={searchTerms}
For some reason it automatically encodes the last part with "searchTerms" whereas I want just the part prior to it to be encoded. The reason is because its a template URL that the client can replace the braces with the search term they want.
In Spring, we create the urls with query parameters and path variables using UriComponentsBuilder as below
Path Variable:
UriComponentsBuilder.newInstance()
.scheme("http")
.host("http://localhost:8080/contextpath/")
.path("/{variable1}/{variable2}/")
.build()
.expand("value1", "value2")
.encode();
Query parameter
.queryParam("value", "a") for http://localhost:8080/contextpath/?value=a

How to send JSON as a parameter in url using Spring RestTemplate?

I am trying to achieve same thing as this: How to use query parameter represented as JSON with Spring RestTemplate?, sending JSON string as a URL parameter in restTemplate.exchange().
The accepted answer mentions that sending JSON object as request parameter is generally not a good idea since you will probably face problem with curly brackets inside JSON. That is exactly what is happening when I am trying to make a GET call to an API. Since this is an API from another system, I cannot ask them to change the format and will have to call the GET endpoint, passing JSON as parameter. How can I achieve this in restTemplate.exchange() call?
Note: The mentioned related question does not guide on how to overcome this problem and I do not have enough reputation to comment on it to ask the author of the answer.
Answering my own question. While it is a bad idea to pass JSON like this in a query/url parameter, there is a workaround as suggested here: https://jira.spring.io/browse/SPR-9220?focusedCommentId=76760&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-76760.
Replicating the code here in case this link goes dead:
String url = "http://localhost:8983/solr/select?wt=json&indent=true&fl=*&q=*:*&fq={!geofilt}&sfield=venue_location&pt=28.0674,-80.5595&d=25";
URI uri = UriComponentsBuilder.fromUriString(url).build().encode().toUri();
System.out.println(uri);
// http://localhost:8983/solr/select?wt=json&indent=true&fl=*&q=*:*&fq=%7B!geofilt%7D&sfield=venue_location&pt=28.0674,-80.5595&d=25
Basically, instead of passing url having JSON query/url parameters as a string, pass it as a URI. Then call exchange method as before, but with URI instead of String:
restTemplate.exchange(uri, HttpMethod.GET, requestEntity, String.class)
If this is 3rd party API and you cannot control or change JSON processing on backend side - there is no solution. Even if you will encode with URLEncoder - there is no guarantee that API backend would process such request correctly.
You can use URLEncoder class to encode the URL in exchange method, e.g.:
String url = "http://www.yoursite.com/api?param={\"some_key\":\"some_value\"}";
System.out.println(URLEncoder.encode(url, StandardCharsets.UTF_8.name()));
This will encode the characters (like braces and double quotes) and server then will decode it back to json.

How to encode path parameter using Java Jersey

How do you encode a path parameter (not form-url-encoded) but just a single URL that's appended in the format:
public String method(#PathParam("url") String url) {
}
There are lots of references to form URL encoding, but I want to simply encode a string as in the above.
Like mentioned in the previous answer URLEncoder can only be used for query paramaters, not path parameters. This matters e.g. for spaces which are a + in the query parameter but a %20 in the path.
org.springframework.web.util.UriUtils.encodePath()
can be used. Also using an org.apache.http.client.utils.URIBuilder would work. setPath is escaping the path part here. Also pure Java by using a constructor of java.net.Uri works.
Why would you want to *en*code it there, if anything wouldn't you want to *de*code it? In any case, you would call the standard URLEncoder.

Categories

Resources