Quarkus rest client parameter query encoding - java

I have this quarkus rest api:
#ApplicationScoped
#RegisterRestClient(configKey = "s-api")
#RegisterProvider(LoggingFilter.class)
public interface MyClientAdapter {
#GET
#Produces(MediaType.TEXT_PLAIN)
String search(#QueryParam("lodis") double lodis,
#QueryParam("secTcn") String secTcn);
the api works well, but in case I pass this value to the method ussu%os, the rest client encodes it to 'ussu%25os':
restClient.search(28322.2, "ussu%os")
As a result of that the endpoint returns nothing.
So my question is how can I disable that encoding for the queryparam secTcn?

The behaviour of your client is correct - % sign is a reserved character in URIs -see RFC3986. Therefore any client, that wants to pass % in the URI must encode it, resulting in %25 being sent to the server.
It is up to the provider of that API endpoint, to correctly decode the query params to their string literal values. If the provider is Jax-rs, then check the #Encoded annotation, whether the values are passed decode or raw.

Related

QueryParam decode my url encoded with cp1252

I have a get request with this param in the url (encoded in cp1252):
?c=es&t=a%20coru%F1a
I have a Spring Boot service with a QueryParam that automatically converts to:
a coru�a
The %20 are replaced by spaces and the %F1 are replace by �
If I try to encode again:
java.net.URLEncoder.encode(t, "Windows-1252");
This is the final result (%3F instead %F1)
a+coru%3Fa
What I need is the QueryParam doesn't decode the url, I only want that string as a I send it.
If I try with POST request and x-www-form-urlencoded everything works fine (obviously), but I need GET request.
This is what i did it at the end:
I've changed #RequestParam by:
HttpServletRequest request
And then:
request.getQueryString()
And I can get the values from the query url in the same format.
Probably it's not the best option, but it works!
Thanks.

How to suppress url encoding with spring boot

I have created a GET/POST API using Spring boot which has a http url parameter say refid. Now this parameter is already encoded before invoking GET/POST request
e.g. http://localhost:8080/users/TESTFNkJXiQAH%2FJBKxigBx
But, when I deploy this through Spring Boot, the encoded refid is encoded again and the refid changes. i.e. it becomes:
http://localhost:8080/users/TESTFNkJXiQAH%252FJBKxigBx
I want to suppress this 2nd encoding by Spring boot. Can anyone advise here?
Don't know if you are still having this problem or you found out why it's happening, but because I was trying to explain to someone the phenomenon, I looked if there is already a good explanation. But since you also ask and I didn't find any, here is my answer.
So you encode your refid
TESTFNkJXiQAH%2FJBKxigBx
before you send it through the url, which then you give into a browser. Now this is only the encoded refid. When you call it through a URL directly you have to encode it again, according to the HTML URL encoding standards. That’s why the double escape. Also read this. E.g. so if your refid looks like this
test%123
and you encode it you turn it into
test%25123
now if you also want to pass it through a url on the browser you'd have to encode it again.
test%2525123
But if a service A is using this service and service A encodes this refid properly then you wont have this problem. It's happening only because you are trying to call this api endpoint through the browser.
Of course I take for granted that you are doing this:
String decoded = URLDecoder.decode(refid, "UTF-8");
in your controller
Pass the decoded URL in first place instead of doing inconvenient things to stop double encoding.
You get already decoded field in rest controller.
Example if you pass www.xyz.com?name=nilesh%20salpe
you will get value of param name as "nilesh salpe" and not "nilesh%20salpe"
This is a basic example of URLDecoder:
#RequestMapping(value = "/users/{refId}", method = GET)
public void yourMethod(#PathVariable("refId") String refId) {
// This is what you get in Spring Boot
String encoded = refId; //"TESTFNkJXiQAH%252FJBKxigBx"
String decoded = URLDecoder.decode(encoded, "UTF-8");
System.out.println(decoded);
// Result TESTFNkJXiQAH%2FJBKxigBx
}

Url encoding issue with Jersey Client

I need to make a service call such as this:
http://myservice.com/path?var1=value1&var2=value2
The issue I have is value1 and value2 ends up getting encoded, and this makes the service call fail. For example, value1 is something like "a=b&b=c;2&&="... it contains special characters, basically.
I am guessing that this is an issue for the service to fix - to properly handle decoding encoded characters, which I do not think it is currently doing.
Here is a sample of how I am making these requests:
WebTarget target = client.target("http://test.com")
.path("path1")
.queryParam("var1", var1);
Builder builder = target.request();
...
What's puzzling to me is that if I make the same request just using Chrome, everything works. So that makes me to believe that I should have some way with the Jersey API of "disabling" the encoding.
Only way I have found so far to use "raw" Url is to use URI.
So call like this
URI uri = URI.create("http://localhost/~Common~0#/edit?vadf&&sfs&&fdsfd=fs&fsd");
WebTarget target = client.target(uri);
You get request url
1 > GET http://localhost/~Common~0#/edit?vadf&&sfs&&fdsfd=fs&fsd
Everything else I tried resulted in encoding special characters.

Get fragment (value hash '#') from a URL in jersey #PathParameter

How can I get the fragment (value hash '#') from a URL using Jersey #PathParameter?
#Path("Step2")
public class AdResource {
#GET
#Produces(MediaType.APPLICATION_JSON)
#Path("/{password:.+}/")
public String doResc(#PathParam("password") String pwd){
System.out.println(pwd);
}
My URL is http://localhost:8080/Sample/webapi/Step2/Password#12#
but the password will be display "Password#12" only the hash(#) is missing..
Try to encode/decode the url.
for javascript:
encodeURI(uri)
then decode it in java using URLDecoder
Since you seem to have a hash in your actual value, and it's not meant to be a fragment, it needs to be encoded before sending. URL encoding is the proper way to do it (like the other answer suggests).
Note also that there are other issues sending password in the url, such as it will be stored in different access logs, it will be part of browser url history etc. Usually you should not send it that way. Prefer POST body.

Return file or plain text

I have to create a rest web service where in user access data using url. Url has a query parameter named format which can be either text or file. If user chooses text as format then I have to return text data to browser or if user chooses file as format then return a file for user to download. How can I achieve this?
What I have tried so far (not working) :
#GET
#Produces({MediaType.TEXT_PLAIN, MediaType.APPLICATION_OCTET_STREAM})
#Path("/some_path")
public Response some_path (#Context HttpServletRequest request) {
String format = null;
if(request.getParameterValues("format") != null && request.getParameterValues("format")[0] != null) {
format = request.getParameterValues("format")[0].toString();
}
else {
format = "text";
}
File file = new File("/some/file/path.txt");
if(format.equals("text")) {
return Response.status(200).entity("sending some text").build();
} else {
return Response.ok(file, MediaType.APPLICATION_OCTET_STREAM).header("content-disposition","attachment; filename = result.txt").build();
}
}
With above code format=text works properly but format=file throws HTTP Status 406 null error.
Thanks In Advance
The HTTP status you get is
406 Not Acceptable
To quote Wikipedia:
The requested resource is only capable of generating content not acceptable according to the Accept headers sent in the request.
So you client doesn't send a HTTP header of
Accept: text/plain
or
Accept: application/octet-stream
or any combination. Check your client and the header it sends.
You are mixing to approaches. The first, quite popular but not standardized, by providing the hint of the expected result in request's path by using the format parameter (BTW you may use the #QueryParam("format") String format rather than extracting it from ServletRequest). The second approach is the HTTP content negotiation mechanism, in this case using Accept/Content-Type headers. This mechanism is handled by the JAX-RS implementation based on #Produces annotation and providers' classes.
So now, your user is not only required to set the format but also Accept header. It seems that you are using the client which sets the Accept and one of its value is text/plain. That is why it the first case is working, but there is no application/octet-stream or */* (all), so you the JAX-RS expects that the client is not able to process such a content and instead sends him an error 406 Not Acceptable.
The solution here is to remove the #Produces annotation (you are the one who is taking care of the format of the response), or drop the format parameter and let the JAX-RS do his work (probably you will need to register your own provider). If you however stay with your solution then make sure that the correct or no Accept header is send in request (no header means: "I would accept whatever you send").

Categories