I do not know Java and I haven't had success with Google or trial and error testing...
How would I write this with just using CURL on the command line for a RESTful API authentication? (a php or perl solution would also be okay)
This code is from documentation but I don't plan on using Java and need to translate it.
URL url = new URL("http://www.thingsandstuff.com/resfulness/post");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
// i don't know if this is relevant to my question or not...
conn.setRequestMethod("POST");
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setRequestProperty("Content-Type","application/x-www-form-urlencoded");
// this is what i think might be the problem...
String userNamePassword = "myusername:mypassword";
userNamePassword =
new String(org.apache.commons.codec.binary.Base64.encodeBase64(userNamePassword
.getBytes()));
conn.setRequestProperty("Authorization", userNamePassword);
I always get a 401 unauthorized error.
I've been just playing with the header argument -H. I don't know if what I am doing is not working because I am truly not doing the authentication right or if it is something else. The data is xml and I am testing with something very simple/straightforward. I am assuming that even if my data/xml/post is incorrect, it would be returning an error instead of an unauthorized.
# bXl1c2VybmFtZTpteXBhc3N3b3Jk == myusername:mypassword base64 encoded....
curl -H "bXl1c2VybmFtZTpteXBhc3N3b3Jk" -d "<datums>" -X POST http://www.thingsandstuff/restfulness/post
curl -H "bXl1c2VybmFtZTpteXBhc3N3b3Jk" -d "<datums>" -X POST http://www.thingsandstuff/restfulness/post
# and like this... with encoded things and not encoded things...
curl -d "<datums>" -X POST http://user:password#www.thingsandstuff.com/restfulness/post
curl -u user:password -d "<datums>" -X POST http://www.thingsandstuff.com/restfulness/post
And for all three, I've tried encoding just the password, both together, both separately, neither... And I'm sure it doesn't help that my username does have a \ and the password does end in an ! but I think, when I'm not encoding them, I am escaping properly.
And the curl man page says that -d will cause curl to pass the data to the server using the content-type application/x-www-form-urlencoded, so that means I don't need to pass an additional header saying the content-type, right? Basically... I only partially know what I'm doing and it doesn't work and there are too many things I don't know about enough to isolate my issue or probably even correct it (yes, just enough to be dangerous).
The reason you are getting the 401 is the Authorization header needs a scheme prefix, in your case Basic
So currently you are sending
Authorization: <base64(username:password)>
But the web server expects
Authorization: Basic <base64(username:password)>
as described here
this change should work:
conn.setRequestProperty("Authorization", "Basic " + userNamePassword);
Okay, so this is what I ended up with...
curl -H "Authorization:dXNlclxuYW1lOnBhc3N3b3JkIQ==" -X POST -d 'data=%3C%3Fxml+version....' http://www.stuffandthings.com:8080/restfulness/post
So... username:password is base 64 encoded together. The data is encoded by ISO/IEC 8859-1 and prefixed with "data=" this particular set restful service.
I ended up putting it in PHP just because it was easier to test continuously that way. And this is what ended up working for that...
$user = 'user\\name';
$pass = 'password!';
$userpass = base64_encode($user.':'.$pass);
$url = 'http://www.thingsandstuff.com:8080/restfulness/post';
if (($handle = fopen("foo.csv", "r")) !== FALSE)
{
while (($data = fgetcsv($handle, 1000, ",")) !== FALSE)
{
list($thing1,$thing2) = $data;
$xml = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>
<entry xmlns=\"http://purl.org/atom/ns#\">
<xml data goes here>
<ns:thing1>$param1</ns:thing1>
<ns:thing2>$param2</ns:thing2>
</xml data goes here>
</entry>";
$datums = 'data='.utf8_decode($xml);
$result = do_curl($url,$datums);
// not actually using the response at this
// point... just running through everything
var_dump($result);
}
fclose($handle);
}
function do_curl($url, $data) {
global $userpass, $user, $pass;
$ch = curl_init();
$header = array('Authorization:'.$userpass,
'Content-Type:application/x-www-form-urlencoded',
'Content-Length:'.strlen($data));
// this line was the last thing to be added before it worked
// i didn't try it again, removing the authentication in $header
// to see if this was the only thing actually needed...
curl_setopt($ch, CURLOPT_USERPWD, $user.':'.$pass);
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, $header);
curl_setopt($ch, CURLINFO_HEADER_OUT, true);
curl_setopt($ch, CURLOPT_NOBODY, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
$result = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$hout = curl_getinfo($ch, CURLINFO_HEADER_OUT);
//echo "\n"; var_dump($hout); echo "\n";
curl_close($ch);
return array('status'=>$status, 'result'=>$result);
}
And If I var_dump($hout) from the do_curl function... the header actually sent was:
POST /resfulness/post HTTP/1.1
Authorization: Basic dXNlclxuYW1lOnBhc3N3b3JkIQ==
Host: www.thingsandstuff.com:8080
Accept: */*
Content-Length: 409
Content-Type: application/x-www-form-urlencoded
<?xml version="1.0" encoding="UTF-8" ?>
<entry xmlns="http://purl.org/atom/ns#">
<xml data goes here>
<ns:thing1>value1</ns:thing1>
<ns:thing2>value2</ns:thing2>
</xml data goes here>
</entry>
Related
For some reason zip files produced on nodeJS gets rejected on a Java server where you can only use "binary" data upload.
If I post the file with Postman using binary it works fine, but when sending through nodeJS (request/request-promise/http ...etc) it does not work.
It gives:
java.util.zip.ZipException: only DEFLATED entries can have EXT descriptor
at java.util.zip.ZipInputStream.readLOC(ZipInputStream.java:310)
at java.util.zip.ZipInputStream.getNextEntry(ZipInputStream.java:122)
at com.ws...
The files are valid (it accepts via postman!)
Spent nearly two days on this issue. Read through tons on stack overflow post (most of them did not have proper answer in this specific topic) and googled around, but all the efforts in vain.
I kept experimenting and the only solution which seemed to work just fine is using child process and curl...
In case someone else falls into this really annoying problem:
var exec = require('child_process').exec;
var args = "-X POST \
https://mywebsite.com/zip-upload \
-H 'Authorization: Bearer gFChWxzeCIZVLM2q...WlvDB6zq2uOHfUcdX' \
-H 'Cache-Control: no-cache' \
-H 'Content-Type: application/zip' \
--data-binary #./data.zip";
exec('curl ' + args, function (error, stdout, stderr) {
console.log('stdout: ' + stdout);
console.log('stderr: ' + stderr);
if (error !== null) {
console.log('exec error: ' + error);
}
});
In my opinion, child_process is the last choice. If you have tried request or request-promise and failed, how about trying htp:
const htp = require('htp');
htp.post(
"https://mywebsite.com/zip-upload",
{ "Authorization" : "earer gFChWxzeCIZVLM2q...WlvDB6zq2uOHfUcdX"
, "Cache-Control" : "no-cache"
, "Content-Type" : "application/zip"
},
fs.createReadStream("./data.zip")
)
.then(function(response) { /* ... */ })
.catch(function(error) { /* ... */ })
;
I was facing similar problem. In my case, I was using custom value for Content-Type (e.g. - "application/abc+json") to upload a zip file via POST request in fetch(). It was working in Postman, but not in nodejs server.
I was able to get it working by adding Content-Length as header before making request via fetch().
Request headers I used - Content-Type, Content-Length, Authorization, and bunch of other API specific headers.
Hopefully this helps anyone facing issue.
I'm recieving 'null' on my Params.
So far i've found people using "PathParams", "FormParams" and "QueryParams" on java to get their variables from the request, however in my case, using post i dont have PathParams, and for some reason FormParams and QueryParams are returning null as if i had never sent them. So i'd like help to solve this.
My php cURL POST request:
<?php
$url = "http://localhost:8080/TestRest/test/asd";
$params = "param1=val1¶m2=val2";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POSTFIELDS, urlencode($params));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_HEADER, 0);
$result = curl_exec($ch);
curl_close($ch);
echo $result;
?>
My java Web Service:
#Path("/test")
public class Streams {
#POST
#Path("/asd")
#Produces(MediaType.TEXT_PLAIN)
#Consumes({"application/x-www-form-urlencoded"})
public String addStream(#FormParam("param1") String param1,
#FormParam("param2") String param2) {
return "param1 = "+param1;
}
}
For some reason param1 is null.
What am i doing wrong?
I am going out on a limb and saying your problem may stem from this:
urlencode($params);
For instance: a=1&b=2&c=3 is perfectly valid.
urlencode('a=1&b=2&c=3') goes to this: a%3D1%26b%3D2%26c%3D3 and your webservice may not understand what it is your are passing. It is looking for a=...&b=...&c=... and you are not giving it any of that.
Try leaving off the urlencode() and seeing if it works. If it does, and you still want to ensure content like this&this is encoded properly, then you will need to parse the url parameters, encode them, and then recombine them for the post data.
$ch = curl_init();
curl_setopt($ch, CURLOPT_FILE, $file);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_URL, $urls[$vidCount]);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_exec($ch);
curl_close($ch);
So I have a cURL request that takes a URL and produces a file in the filesystem.
How do I emulate the above PHP cURL request in Java?
I have tried HttpURLConnection, but I am getting 403 Forbidden. The same call in cURL works properly. Is there some architecture difference between the two that I need to reconcile?
I believe it could be something in the headers that cURL might be setting automatically where Java is not. I'm not really sure but I would appreciate any advice I can get.
Thanks.
I am not sure why you trying to emulate PHP behavior in Java. If the end result is really what you need to reach, than use the Java HttpURLConnection or even URLConnection.
These are the steps:
POST Form (file/image input) from the browser goes to a PHP server.
The PHP server then use fsockopen to a Java (GlassFish/Jersey) REST service, sending the image as content for more advanced imaging work to be done there, and returning the resulting image back to the PHP server (or returning only a URI to the image).
The PHP server then echos the result (img src= ..) back to the user in the HTML document.
Getting the image and all its attributes in the first step works great, but I need help setting up the headers correctly in the POST request from PHP to the web service.
Current code:
$fp = fsockopen("domain..", 80, $errno, $errstr, 30);
$contentlength = $_FILES["photo_file"]["size"];
$imageref = $_FILES["photo_file"]["tmp_name"];
$out = "POST /Uri to resource .. HTTP/1.1\r\n";
$out .= "Host: http://... \r\n";
$out .= "Connection: Keep-Alive\r\n";
$out .= "Content-type: multipart/mixed\r\n";
$out .= "Content-length: $contentlength\r\n\r\n";
$out .= "$imageref";
fwrite($fp, $out);
$theOutput;
while (!feof($fp))
{
$theOutput .= fgets($fp, 128);
}
echo $theOutput;
fclose($fp);
Which echoes to the browser: "HTTP/1.1 400 Bad Request Content-Type: text/html Content-Length: 717".
So I need better formed headers to get through to the REST web-method. And if I should achieve that does anyone know what paramaters to use in the jersey web-method to access the image?
For standard HTML forms its this:
#Consumes(MediaType.MULTIPART_FORM_DATA)
public Response getFullImage(#FormDataParam("photo_file") InputStream imageIS {..ImageIO.read(imageIS)..}
Would love suggestions to better architecture also for achieving this in HTML.
Cheers
You probably have problem with badly written request and should use cURL at first place (in php), basic example usage (with writing to the file) from manual page:
$ch = curl_init("http://www.example.com/");
$fp = fopen("example_homepage.txt", "w");
curl_setopt($ch, CURLOPT_FILE, $fp);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_exec($ch);
curl_close($ch);
fclose($fp);
Another example for setting post data from curl_setopt() page:
$data = array('name' => 'Foo', 'file' => '#/home/user/test.png');
curl_setopt($ch, CURLOPT_URL, 'http://localhost/upload.php');
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
And handling HTTP status codes via curl_getinfo():
if(curl_getinfo($c, CURLINFO_HTTP_CODE) === 200){
...
}
You also may set http headers manually:
curl_setopt($cURL,CURLOPT_HTTPHEADER,array (
"Content-Type: text/xml; charset=utf-8",
"Expect: 100-continue"
));
This question already has answers here:
Read error response body in Java
(8 answers)
Closed 3 years ago.
When I contact a web service using a Java HttpUrlConnection it just returns a 400 Bad Request (IOException). How do I get the XML information that the server is returning; it does not appear to be in the getErrorStream of the connection nor is it in any of the exception information.
When I run the following PHP code against a web service:
<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://www.myclientaddress.com/here/" );
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1 );
curl_setopt($ch, CURLOPT_POST,1 );
curl_setopt($ch, CURLOPT_POSTFIELDS,"username=ted&password=scheckler&type=consumer&id=123456789&zip=12345");
$result=curl_exec ($ch);
echo $result;
?>
it returns the following:
<?xml version="1.0" encoding="utf-8"?>
<response>
<status>failure</status>
<errors>
<error name="RES_ZIP">Zip code is not valid.</error>
<error name="ZIP">Invalid zip code for residence address.</error>
</errors>
</response>
so I know the information exists
HttpUrlConnection returns FileNotFoundException if you try to read the getInputStream() from the connection, so you should instead use getErrorStream() whenever the status code is equal or higher than 400.
More than this, please be careful since it's not only 200 to be the success status code, even 201, 204, etc. are often used as success statuses.
Here is an example of how I went to manage it
// ... connection code code code ...
// Get the response code
int statusCode = connection.getResponseCode();
InputStream is = null;
if (statusCode >= 200 && statusCode < 400) {
// Create an InputStream in order to extract the response object
is = connection.getInputStream();
}
else {
is = connection.getErrorStream();
}
// ... callback/response to your handler....
In this way, you'll be able to get the needed response in both success and error cases.
Hope this helps!
If the server is returning XML and you pass the parameters as a url, why not just use a library that supports JAX-RS (Java's REST webservices API), such as Apache CXF?
I know it supports JAX-RS because it has a chapter in the manual.
I had same issue and adding below two lines resolved it.
httpConn.setRequestProperty("Connection", "Close");
System.setProperty("http.keepAlive", "false");