Does Java handle cURL differently? - java

I'm trying to execute a POST request using curl in order to do some authorization. The expected result is a token which will be provided in the Location response header
Issue
If I execute the command from within my bash, it'll work just fine (= with redirections etc.)
If I execute the exact same command (really just copy&paste) in my Java application, I get a slightly different result ( = missing token in the Location response header)
Expected result
Token located in the Location response header, like Location: /https://localhost:4200/token=123
Actual result
Some kind of error, like Location: my.policy
Command
This is the basic structure of the command. Basically, it is a POST request with some redirection involved.
curl -L -v --header \"something:special\” --cookie \"a=1;b=2\" --data \"param1&param2\" https://url
What I've tried
Enabled the verbose mode via -v
Enabled redirection via -L
Checked for handshake (or common) errors
Checked for typos and encoding issues
Executed command within the bash
Tried executing the command using a Java based approach
Even tried to execute the command creating a bash from within the code and passing the command
Java code
String command = "SOME CURL COMMAND USING POST"
// execute the command
Process process = Runtime.getRuntime().exec(command);
// Since we will get a 302 (as expected), the result will be in the error stream
Scanner scanner = new Scanner(process.getErrorStream());
// Do some formatting...
String tmp = "";
while (scanner.hasNext()) {
String t = scanner.next();
if (t.equals("*") || t.equals("<") || t.equals(">")) {
tmp += "\n";
}
tmp += t + " ";
}
System.out.println("Content" + tmp);
Question
Is Java handling the execution differently? Because I don't see why I get a different result
Any help is appreciated.
Best

Related

Executing curl command in Java and getting response as String

I am trying to execute a curl command and get a part of the response as a string.
The command that I am trying to execute is as follows
curl -X POST "https://kakaoapi.aligo.in/akv10/token/create/30/s/" \
--data-urlencode "apikey=xxxxx" \
--data-urlencode "userid=xxxxx"
The response that I get when I execute this in the terminal is as follows
{"code":0,"message":"\uc815\uc0c1\uc801\uc73c\ub85c \uc0dd\uc131\ud558\uc600\uc2b5\ub2c8\ub2e4.","token":"tokenvalue","urlencode":"urlencoded"}%
The java code that I am trying to execute to get this result is something like this
String command =
"curl -X POST \"https://kakaoapi.aligo.in/akv10/token/create/30/s/\" \\\n" +
"\t--data-urlencode \"apikey=xxxxx\" \\\n" +
"\t--data-urlencode \"userid=xxxxx\"";
Process pr = Runtime.getRuntime().exec(command);
String result = new BufferedReader(
new InputStreamReader(pr.getInputStream()))
.lines()
.collect(Collectors.joining("\n"));
log.info(result);
I am currently getting a null value in the log.
It would be greatly appreciated if anyone could tell me what I am doing wrong, or suggest a better way of doing this.
I have tried doing this by creating a httpclient and sending a post request, and I did get a response but the authentication failed for some reason.
Thank you in advance!
A better way of doing this is by using Unirest library (http://kong.github.io/unirest-java):
Unirest.setTimeouts(0, 0);
HttpResponse<String> response = Unirest.post("https://kakaoapi.aligo.in/akv10/token/create/30/s/?apikey=xxxxx&userid=xxxxx")
.asString();
The first step is to install it's maven / gradle dependency and then try the code above.

Curl: how data is interpreted by Java InputStream, if I sent it using curl --data-binary?

I have a server, written on Java, which is currently running on a
http://localhost:8080
Source code is hidden from me, but I know that all endpoints are handled by Java HttpExchange class, for example endpoint:
http://localhost:8080/generate/init
will be handled like that:
public void init(HttpExchange httpex) throws IOException {
...
}
The next thing I know is that incoming POST requests are handled like that:
byte post_data = (byte) httpex.getRequestBody().read();
My question is, that when I do from a command-line:
echo -e '\x03' | curl -X POST -i --data-binary #- http://localhost:8080/generate/init
What will be the value of post_data?
As I understand curl will send '\x03' exactly as it is:
\x03
And Java HttpExchange method getRequestBody() will return InputStream of it, where read() will translate that InputStream into int. As much as I know, Java doesn't interpret HEX as '\x03', instead it uses Unicode '\u0003'. Therefore I'm afraid of sending wrong data into my server.
If I'm wrong about curl --data-binary, please correct me! I just wish
to be sure, that I pass number "3" by POST request and server
interprets it as number 3, but in bytes ((byte) 3)

Hyperledger Composer + loopback-datasource-juggler + Java: Encoding Problems

I developed a Business Network Definition with Hyperledger Composer, deployed it on a Hyperledger Fabric example-chain (running locally on a VirtualBox-installation of Ubuntu with Docker-containers) and started Composer's REST-server with composer-rest-server (and options -c [cardname] -n always -w true). Then I played a bit in the browser and all is working fine.
Now comes the problematic bit: I want to write a Java-program interacting with this REST API and somehow the API seems unable to parse my Java-sent requests. I copied the JSON-string that Java produces to the browser, ran it there and it worked fine. But if I send it programmatically I get the error (see at the end).
This is what I send through the browser
{"cId":"C_ID7","cDomain":"example.com"}
The browser tells me with CURL it should look like this
curl -X POST --header 'Content-Type: application/json' --header 'Accept: application/json' -d '{"cId":"C_ID7","cDomain":"example.com"}' 'http://localhost:3000/api/com.example.Company'
Now I want to send the same message through Java+JSOUP with the following code:
Response resp = Jsoup.connect(baseURL + namespace + "Company").ignoreContentType(true).method(Method.POST)
.ignoreHttpErrors(true)
.requestBody("{\"cId\":\"C_ID7\",\"cDomain\":\"example.com\"}").execute();
The same (without the requestBody and Method.GET) works for GET-requests. ignoreContentType(true) is necessary, because JSOUP will not handle 'application/json', see here. ignoreHttpErrors(true) is necessary, to get through the Http 500 error, which conceals the true error, which I need for trouble-shooting.
So then finally what I see, when I execute the above code, is the following error:
{"error":{"statusCode":500,"name":"Error","message":"Property names containing dot(s) are not supported. Model: com_example_Company, dynamic property: {\"cId\":\"C_ID7\",\"cDomain\":\"example.com\"}","stack":"Error: Property names containing dot(s) are not supported. Model: com_example_Company, dynamic property: {\"cId\":\"C_ID7\",\"cDomain\":\"example.com\"}\n at com_example_Company.ModelBaseClass._initProperties
(/home/[user]
]/.nvm/versions/node/v8.9.4/lib/node_modules/composer-rest-server/node_modules/loopback-datasource-juggler/lib/model.js:249:17)\n
at com_example_Company.ModelBaseClass (/home/[user]/.nvm/versions/node/v8.9.4/lib/node_modules/composer-rest-server/node_modules/loopback-datasource-juggler/lib/model.js:60:8)\n
at com_example_Company.Model (eval at createModelClassCtor
(/home/[user]/.nvm/versions/node/v8.9.4/lib/node_modules/composer-rest-server/node_modules/loopback-datasource-juggler/lib/model-builder.js:671:21), <anonymous>:12:24)\n
at com_example_Company.PersistedModel (eval at createModelClassCtor
(/home/[user]/.nvm/versions/node/v8.9.4/lib/node_modules/composer-rest-server/node_modules/loopback-datasource-juggler/lib/model-builder.js:671:21), <anonymous>:12:24)\n
at new com_example_Company (eval at createModelClassCtor
(/home/[user]/.nvm/versions/node/v8.9.4/lib/node_modules/composer-rest-server/node_modules/loopback-datasource-juggler/lib/model-builder.js:671:21), <anonymous>:12:24)\n
at Function.DataAccessObject.create (/home/[user]/.nvm/versions/node/v8.9.4/lib/node_modules/composer-rest-server/node_modules/loopback-datasource-juggler/lib/dao.js:359:13)\n
at SharedMethod.invoke
(/home/[user]/.nvm/versions/node/v8.9.4/lib/node_modules/composer-rest-server/node_modules/strong-remoting/lib/shared-method.js:270:25)\n
at HttpContext.invoke (/home/[user]/.nvm/versions/node/v8.9.4/lib/node_modules/composer-rest-server/node_modules/strong-remoting/lib/http-context.js:297:12)\n
at phaseInvoke (/home/[user]/.nvm/versions/node/v8.9.4/lib/node_modules/composer-rest-server/node_modules/strong-remoting/lib/remote-objects.js:676:9)\n at runHandler
(/home/[user]/.nvm/versions/node/v8.9.4/lib/node_modules/composer-rest-server/node_modules/strong-remoting/node_modules/loopback-phase/lib/phase.js:135:5)\n
at iterate (/home/[user]/.nvm/versions/node/v8.9.4/lib/node_modules/composer-rest-server/node_modules/strong-remoting/node_modules/loopback-phase/node_modules/async/lib/async.js:146:13)\n
at Object.async.eachSeries
(/home/[user]/.nvm/versions/node/v8.9.4/lib/node_modules/composer-rest-server/node_modules/strong-remoting/node_modules/loopback-phase/node_modules/async/lib/async.js:162:9)\n
at runHandlers (/home/[user]/.nvm/versions/node/v8.9.4/lib/node_modules/composer-rest-server/node_modules/strong-remoting/node_modules/loopback-phase/lib/phase.js:144:13)\n
at iterate
(/home/[user]/.nvm/versions/node/v8.9.4/lib/node_modules/composer-rest-server/node_modules/strong-remoting/node_modules/loopback-phase/node_modules/async/lib/async.js:146:13)\n
at /home/[user]/.nvm/versions/node/v8.9.4/lib/node_modules/composer-rest-server/node_modules/strong-remoting/node_modules/loopback-phase/node_modules/async/lib/async.js:157:25\n
at /home/[user]/.nvm/versions/node/v8.9.4/lib/node_modules/composer-rest-server/node_modules/strong-remoting/node_modules/loopback-phase/node_modules/async/lib/async.js:154:25"}}
where obviously [user] is my username. So I had a look at the loopback-datasource-juggler sources and found that in model-builder.js (source on Github) instead of parsing the different properties of the string, it is given the complete string ("{\"cId\":\"C_ID7\",\"cDomain\":\"example.com\"). In line 269 the builder checks whether there are dot-characters in the property-name. Since in our case the property name is the complete JSON-string, there are dots and the program fails.
Unfortunately XML does not seem to be supported at this point.
Now: How can this happen? My only guess is an encoding thing done by Java, because the same JSON works in the browser. Any ideas what could have caused this?
And one smaller issue: The error message in the code is ''Property names containing dot(s) are not supported. ' + 'Model: %s, property: %s'', but in the error I receive it says something about "dynamic property". Am I at the wrong point for searching what causes the error?
Since you have already specified 'Content-Type: application/json', you needn't have double quotes in the requestBody. The following should work:
Response resp = Jsoup.connect(baseURL + namespace + "Company").ignoreContentType(true).method(Method.POST)
.ignoreHttpErrors(true)
.requestBody({\"cId\":\"C_ID7\",\"cDomain\":\"example.com\"}).execute();
the curl example is what the REST APIs (rather than merely the browser) know about the business network REST API endpoints.
for your requestBody, you will need the fully qualified class (ie meaning asset/participant/transaction class with leading namespace) - an example is :
curl -X POST --header 'Content-Type: application/json' --header 'Accept: application/json' -d '{ \
"$class": "org.example.biznet.SampleAsset", \
"assetId": "1", \
"value": "103300" \
}' 'http://localhost:3000/api/SampleAsset'
So yours will be something like
Response resp = Jsoup.connect(baseURL + namespace + "Company").ignoreContentType(true).method(Method.POST)
.ignoreHttpErrors(true)
.requestBody("{\"\$class\": \"org.example.biznet.SampleAsset\", \"cId\":\"C_ID7\", \"cDomain\":\"example.com\"}").execute();
I believe you also needed at least one other double-quotes (total above now : 14) and a closing curly bracket in addition.

Convert Python request with image to cURL

I found this example of a API request. Unfortunately I didn't find any other example how to upload an image to the API.
As I'm not familiar with Python I'm trying to understand how to do the same in a cURL command.
import requests
auth_headers = {
'app_id': 'your_app_id',
'app_key': 'your_app_key'
}
url = 'https://XXXXXXX'
files = {
'source': open('media/test.jpg')
}
data = {
'timeout': 60
}
response = requests.post(url, files=files, data=data, headers=auth_headers)
I tried to convert it by trying out a cURL to python converter, but I don't know how to build it with the files.
In the end I want to do the request in JAVA, but I think if I would know the request in cURL I can figure it out.
Hope anyone can help me with that.
This will do it:
#!/bin/bash
args=(
-H 'app_id: your_app_id'
-H 'app_key: your_app_key'
-F 'source=#/path/to/file'
-F 'timeout=60'
'http://httpbin.org/post'
)
curl "${args[#]}"
or, as a one-liner:
curl -H 'app_id: your_app_id' -H 'app_key: your_app_key' -F 'source=#/path/to/file' -F 'timeout=60' 'http://httpbin.org/post'
Use -H to specify header fields (repeat for every field) and -F to specify form fields - either as key=value pairs, or filename=#path pairs. When -F is used, POST method is the default, and Content-Type is multipart/form-data (but that too can be overridden).

Using curl to output http status code, total time, and the request body

I would like to use curl to capture the following parameters in a single POST request:
http status code
total time of the operation
body of the results
Based on the manual (http://curl.haxx.se/docs/manpage.html), here are the options I tried.
1) The -w parameter captures the http_code and the time_total.
curl "http://stackoverflow.com/" -w "\' %{http_code}\',\'%{time_total}\'"
But it appears it only returns these two parameters and I am no longer able to capture the body.
2) The -i parameter returns the header and the requested body but I will no longer be able to return the total time.
curl -i "http://localhost:8080/"
The end goal is place the three results into a JSON object which can then be parsed as needed.
{"httpVar: "200", "runtimeVar" : "18.58", "outputVar" : "ID:grinvriar080n23nvn"}
Currently, I'm using groovy script (similar to JAVA) so I don't think I could use bash or PHP. I could total time it took the groovy to run the .execute() but that won't be the true time it took to POST to send/return data. I'm even open to using another program besides curl.
I looked for a few days now with no results so any suggestions are appreciated.
What you tried should give, what you desired to get.
I mean the following:
curl "http://stackoverflow.com/" -w "\' %{http_code}\',\'%{time_total}\'"

Categories

Resources