I am using the following code to make a http client ,i am facing problem in execute method ,its getting stuck there.
public static final HttpHost target = new HttpHost("test.xyz.com", 443, "https");
public static void test()
{
HttpEntity responseEntity = null;
DefaultHttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost("/xyz/test");
System.out.println("post is " +post.getRequestLine());
UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(username, password);
AuthScope authScope = new AuthScope(target.getHostName(), target.getPort());
System.out.println("auth scope is " +authScope);
client.getCredentialsProvider().setCredentials(authScope, credentials);
//i am passing a xml here
post.setEntity(new StringEntity(xml, "UTF-8"));
post.addHeader("Content-Type", "application/xml");
post.addHeader("Accept", "application/xml");
System.out.println("post " +post.getAllHeaders().length);
HttpResponse response = client.execute(target, post); //getting stuck here no response at all
System.out.println("response " +response.getStatusLine());
responseEntity = response.getEntity();
System.out.println("response entity " +responseEntity);
String responseXmlString = EntityUtils.toString(responseEntity);
System.out.println("response" +responseXmlString);
}
i am facing problem here
HttpResponse response = client.execute(target, post);
what might be wrong ?
The problem is the code is getting stuck in client.execut method its not moving furthur neither i am getting any response.Do i have to set any proxy?
Probably your request is not really 'stuck' but just waiting on a TCP connection timeout, which bu default could be quite lonkg - like 5 minutes or so. There should be a way to set timeout to shorter value - take a look at javadoc for your http client or just try to wait longer.
Also you can take a thread dump while your program is stuck to see where the thread is blocked (see jps and jstack utilities in Sun's JDK)
I think you first need to eliminate the possibility of your server misbehaving. Have you tried POSTing to that URL from outside of your program. Try something like this if you are on a unix-like system or are on windows and have cygwin:
cat <yourfile.xml> | curl -X POST -H 'Content-type: text/xml' -d #- https://test.xyz.com:443/xyz/test
If the POST is successful get a thread dump of your program and post it here for us to take a look.
Related
UPDATE
My problem turned out to be due to some super-class weirdness. However, the urlEncode in this example is wrong. In this case it was also unnecessary. If needed it should be done by each key and value without encoding & or =.
Other than that, this code is correct.
The (scala) code below fails because the server does not seem to receive the body.
The warning on the server log is:
WARNING *** OAuthTokenProcessor caught a OAuthRequestProblemException with message OAuthProblemException{error='invalid_request', description='Missing grant_type parameter value', uri='null', state='null', scope='null', redirectUri='null', responseStatus=0, parameters={}}
I am certain that the params are correct. The url is correct, The headers are correct
(This call already works in Postman and Python)
Any hints deeply appreciated!
private def doPostRequest(): Unit ={
try {
val connectionforPost = (new URL(url)).openConnection.asInstanceOf[HttpURLConnection]
val params = "grant_type=password&client_id=xxxx&client_secret=seccret&username=admin&password=xxxx"
val encodedString = URLEncoder.encode(params,"UTF-8")
import java.nio.charset.StandardCharsets
val postData = encodedString.getBytes(StandardCharsets.UTF_8)
val contentlength = Integer.toString(encodedString.length)
connectionforPost.setConnectTimeout(50000)
connectionforPost.setReadTimeout(50000)
connectionforPost.setRequestMethod("POST")
connectionforPost.setDoOutput(true)
connectionforPost.setDoInput(true)
connectionforPost.setInstanceFollowRedirects(false)
connectionforPost.setRequestProperty("User-agent", "test bot")
connectionforPost.setRequestProperty("Content-Type", "application/x-www-form-urlencoded")
connectionforPost.setRequestProperty("Accept", "*/*")
connectionforPost.setRequestProperty("Connection", "keep-alive")
connectionforPost.setRequestProperty("Content-Length", contentlength)
connectionforPost.setRequestProperty("Accept-Encoding", "gzip, deflate")
connectionforPost.setUseCaches(false)
import java.io.DataOutputStream
val wr = new DataOutputStream(connectionforPost.getOutputStream)
wr.write(postData)
if (wr != null) wr.close()
} catch{
case e:Exception => logger.error(e.getMessage,e)
throw e
}
}
It appears that the server complains that you are not logged in. You get an authentication problem exception. How it usually works is that you send a request to the server to login with the user name and password. If the server authenticates you (recognizes your user name and password as valid ones) it sends you a response with an authentication token in the headers. You may see those 2 headers in your response to successful login:
access-control-expose-headers=[Authorization], Authorization=[Bearer ....]
This means that in all your subsequent requests you will need to add a header "Authorization" that will hold the value "Bearer ....". Then the server will recognize this request as coming from an authenticated user.
Also, I suggest that you may use a 3d party HTTP client. Some well-known clients are Appache HTTP client and OK HTTP client. I use my own Http client that I wrote. It is also available as part of a MgntUtils Open Source Library. Here is the link to Maven artifacts and it is also available on Github with source code and JavaDoc. And here is a javadoc page for HttpClient. Here is the code sample on how you may obtain the token and use it:
try {
HttpClient loginClient = new HttpClient();
loginClient.setConnectionUrl("http://your_url/login");
loginClient.setRequestProperty("accept", "application/json;charset=UTF-8");
loginClient.setContentType("application/json");
String result = loginClient.sendHttpRequest(HttpMethod.POST, "{ \"username\": \"your_user_name\", \"password\": \"Your_password\"}");
System.out.println(result);
System.out.println("HTTP " + loginClient.getLastResponseCode() + " " + loginClient.getLastResponseMessage());
System.out.println("Response headers: " + loginClient.getLastResponseHeaders());
String accessControlExposeHeader = loginClient.getLastResponseHeader("access-control-expose-headers").get(0);
String accessKey = loginClient.getLastResponseHeader(accessControlExposeHeader).get(0);
HttpClient workingClient = new HttpClient();
workingClient.setRequestProperty("accept", "application/json;charset=UTF-8");
workingClient.setContentType("application/json");
workingClient.setRequestProperty(accessControlExposeHeader, accessKey);
workingClient.setConnectionUrl("http://yourUrl/yourPath");
System.out.println(workingClient.sendHttpRequest(HttpMethod.GET));
} catch (IOException e) {
System.out.println(TextUtils.getStacktrace(e));
}
Ok so this is my problem.. To share an image post via linkedin api, you first have to register your image file, you do that via a post request in which you send your binary file. Then you use the the image URN in the original request to submit your post. My request goes through, returns 201 code (which should be a successful request) but ends up not posting the image or the text. If i try to post only text, it works. I've tried registering my image using curl, and it posted on linkedin, so i think i'm not sending the binary file in a request properly, this is my request:
HttpClient client = HttpClientBuilder.create().build();
HttpPut request = new HttpPut(uploadUrl);
request.addHeader("Content-Type", "data/binary");
request.setHeader("X-Restli-Protocol-Version", "2.0.0");
request.setHeader("Authorization", "Bearer " + myToken);
File file = new File(pictureUrl);
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
builder.addBinaryBody("upload-file", file);
request.setEntity(builder.build());
HttpResponse response = client.execute(request);
I get code 201 with this code, but it still doesn't post.
This is the curl example of the request that they give on Share API doc.
curl -i --upload-file /Users/peter/Desktop/superneatimage.png --header "Authorization: Bearer redacted" 'https://api.linkedin.com/mediaUpload/C5522AQGTYER3k3ByHQ/feedshare-uploadedImage/0?ca=vector_feedshare&cn=uploads&m=AQJbrN86Zm265gAAAWemyz2pxPSgONtBiZdchrgG872QltnfYjnMdb2j3A&app=1953784&sync=0&v=beta&ut=2H-IhpbfXrRow1'
Can you tell me what is wrong with my java equivalent?
Edit: Forgot to say i even tried calling curl from java, the same code i used in the terminal, and it still didn't work..
Process p;
try {
p = Runtime.getRuntime().exec("curl -i --upload-file" + " " + pictureUrl + " " + "--header \"Authorization: Bearer " + myToken + "\" '" + uploadUrl + "'");
p.waitFor();
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = "";
String outputController = "";
while ((line = reader.readLine()) != null) {
outputController = outputController + '\n' + line;
}
System.out.println("out: ");
System.out.println(outputController);
return true;
} catch (IOException | InterruptedException ex) {
return false;
}
Output returned an empty String.
Edit2: Another funny thing, when i execute the main request, in which i send the text, and media urns that i get after submitting images, i get 201 again, like it's successful, and in the response i even get the post id. Then i try to use the another api endpoint and pull that post using the id i got from the response, and i get all the data, like the post is posted. It even says in the json that i get that lifecycle is PUBLISHED and the status of the medias is READY. Only thing that's different from the json an image post that is on linkedin is that the media object have thumbnails, and in this case they don't, it's just an empty json array.
I found curl to C# converter https://curl.olsh.me/
below is code snippet is generated:
using (var httpClient = new HttpClient())
{
using (var request = new HttpRequestMessage(new HttpMethod("PUT"), "https://api.linkedin.com/mediaUpload/C5522AQGTYER3k3ByHQ/feedshare-uploadedImage/0?ca=vector_feedshare&cn=uploads&m=AQJbrN86Zm265gAAAWemyz2pxPSgONtBiZdchrgG872QltnfYjnMdb2j3A&app=1953784&sync=0&v=beta&ut=2H-IhpbfXrRow1"))
{
request.Headers.TryAddWithoutValidation("Authorization", "Bearer redacted");
request.Content = new ByteArrayContent(File.ReadAllBytes("/test.png"));
var response = await httpClient.SendAsync(request);
}
}
Ok I've solved it, if anyone encounters the same problem, this is what i did wrong. In the request i added a multipart to request body, this is wrong, you just go RAW. So instead of
File file = new File(pictureUrl);
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
builder.addBinaryBody("upload-file", file);
request.setEntity(builder.build());
you just put
request.setEntity(new FileEntity(new File(pictureUrl), ContentType.create(picture.getContentType())));
and then everything goes on ok.
Not familiar with Java, but I had the same problem using Ruby and I fixed it by adding the MIME type of the image I was uploading as the Content-Type in the request headers. So in your specific case it would be:
request.addHeader("Content-Type", "image/png");
Also take a look at my solution using Ruby's RestClient and Minimagick: https://stackoverflow.com/a/54902863/7844946
I was writing with kotlin and after struggling with the same problem for a long time I managed to fix it, for those struggling with the similar problem, I'll leave my sample codes below. For the visual you need to provide a direct URI path, also pay attention to the header structure.
Here are the codes.
var file = File(ImageURI)
val urls = URL(url)
var connection: HttpsURLConnection = urls.openConnection() as HttpsURLConnection
connection.setRequestProperty("Authorization","Bearer " + accesToken)
connection.setRequestProperty("Content-Type", "image/png")
connection.setRequestProperty("cache-control", "no-cache")
connection.setRequestProperty("X-Restli-Protocol-Version", "2.0.0")
connection.requestMethod = "POST"
connection.doOutput = true
connection.doInput = true
var request = DataOutputStream(connection.outputStream)
request.write(file.readBytes())
request.flush()
println("Response: "+connection.responseCode)
I am implementing an Android app that should upload data to CouchDB. Since I have restricted the admin access to one account, I have to authenticate before inserting a new database. And this is what I am currently struggling with: Authenticate and insert a new database. Operating via Terminal and using curl, everything is working out fine the following way:
> curl -X PUT http://admin_name:admin_password#url:port/database_to_be_inserted
First approach
My first approach was to simply do the same via HTTP PUT in my code like that:
private boolean putJSON(String json, String url) {
// url = http://admin_name:admin_password#url:port/database_to_be_inserted
HttpClient client = new DefaultHttpClient();
HttpPut put = new HttpPut(url);
try {
StringEntity stringEntity = new StringEntity(json,"utf-8");
put.setEntity(stringEntity);
put.setHeader("Content-type", "application/json; charset=utf-8");
put.setHeader("Accept", "application/json");
HttpResponse response = client.execute(put);
// ... buffered input reading on response...
return true;
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
However, doing so I retrieve the following error and JSON array:
Authentication error: Unable to respond to any of these challenges: {}
{"error":"unauthorized","reason":"You are not a server admin."}
The point is, that using the same method for inserting a new user works out perfectly. So, if I am using the above method with a correctly formatted user JSON-Dictionary and the following url, the user is inserted correctly.
http://admin_name:admin_password#url:port/_users/org.couchdb.user:user_name
This should prove, that I am using the right admin data at least, shouldn't it?
Second approach
So, by now, I am trying to authenticate using the "Authorization" option in my HTTP PUT's header:
private boolean putDatabase(String userName, String password, String url) {
// url = "http://url:port/database_to_be_inserted"
HttpClient client = new DefaultHttpClient();
HttpPut put = new HttpPut(url);
String authenticationData = userName+":"+password;
String encoding = Base64.encodeToString(authenticationData.getBytes(Charset.forName("utf-8")), Base64.DEFAULT);
put.setHeader("Authorization", "Basic " + encoding);
try {
put.setHeader("Content-type", "application/json; charset=utf-8");
put.setHeader("Accept", "application/json");
HttpResponse response = client.execute(put);
// ... buffered input reading on response...
return true;
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
Still no success in inserting the database. The response I am parsing says:
Host not found
I have double checked the admin name, password, and url and everything seems correct. Does anyone of you see why this might not work out?
Ok, the answer is simple: The above code (at least the one of my second approach) is working fine. My mistake was to not explicitly specify the port via which the CouchDB should be accessed. This is, how I accidentally called the method:
putDatabase("adminName", "adminPassword", "http://url/database_to_be_inserted");
However, this is how I should have called it:
putDatabase("adminName", "adminPassword", "http://url:port/database_to_be_inserted");
Who is using iriscouch like me and does not know which port to specify here, can look it up in the config file. Using Futon this can be found in the entry "httpd > port" here:
> http://your_url_spec.iriscouch.com/_utils/config.html
More general and without Futon this can be found (and if you wish so edited) via command-line in the local.ini of your own CouchDB installation:
~$ cat etc/couchdb/local.ini
OK, few days ago I wrote a block of code in Java that sends post requests to a PHP file in order to store some data in a MySQL database and receive back simple json_encode() strings such as "error_101" responses from PHP and it worked just fine. Yesterday I reinstalled my XAMPP because I've had some problems with openssl PHP extention and now none of my json_encode() reponses return a value. I've checked the phpinfo() and it says that json support is enabled. To mention that values sent to PHP from JAVA are JSON objects as well and the json_decode() works just fine!
Here's my code to send responses from PHP to JAVA:
<?php
header('Content-type: application/json');
echo json_encode("error_101");
?>
Here's the code to get the response in JAVA
HttpParams httpParams = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(httpParams, 10000);
HttpConnectionParams.setSoTimeout(httpParams, 10000);
HttpClient client = new DefaultHttpClient(httpParams);
String url = "http://192.168.254.19/android/register.php";
HttpPost request = new HttpPost(url);
request.setEntity(new ByteArrayEntity(json.toString().getBytes("UTF8")));
request.setHeader("json", json.toString());
HttpResponse response = client.execute(request);
HttpEntity entity = response.getEntity();
String result = null;
if (entity != null) {
InputStream instream = entity.getContent();
InputStreamReader is_reader = new InputStreamReader(instream);
BufferedReader br = new BufferedReader(is_reader);
result = br.readLine();
Log.i("Read from server", result);
Toast.makeText(this, result, Toast.LENGTH_LONG).show();
}
The response I'm getting is "<br />"
You sure you don't have some debug code somewhere up the chain that reads
echo $TesttVar1 . '<br />';
That would also stop the "header()" from working. Turn on ALL errors (error_reporting(E_ALL); ini_set('display_errors', 'on'); ) and that will show you the line the is output, if that's the case.
But to help weed it out if it is json_encode, just return "Error_101" without the function to test. But I don't think you're getting that far down the program.
json_encode needs an array. like
json_encode(array('status'=>'error_101'));
in this case:
header("Content-type: text/html");
echo json_encode("error_101");
it works.
in this other case:
header("Content-type: application/json");
echo json_encode("error_101");
it doesn't work.
It seems a bug!
I'm new to http programming and I'm attempting to authenticate against a website that doesn't use an API and I'm having some trouble. I found a few other questions that seemed to be similar to mine, but none had an answer that worked for me.
I've tried several different approaches but haven't found one that works yet. Actually, I had it work for me once, but didn't check in that code (I know - what was I thinking?). I haven't been able to get back to that working version again. Here are a few things that I've tried so far:
HttpClient client = new DefaultHttpClient(); //or any method to get a client instance, with a 'threadsafe' connection manager or otherwise
Credentials credentials = new UsernamePasswordCredentials(userName, passwd);
((DefaultHttpClient) client).getCredentialsProvider()
.setCredentials(AuthScope.ANY, credentials);
// website is defined as my target website & this constitutes the valid login URL
HttpPost post = new HttpPost(https + website + "/login");
HttpEntity entity = new StringEntity("Username="+ userName +"&Password="+ passwd);
post.setEntity(entity);
HttpResponse response = client.execute(post);
EntityUtils.consume(entity);
entity = response.getEntity();
EntityUtils.consume(entity);
// the protected part of the site is over http after authentication succeeds
HttpGet get = new HttpGet(http + website +"/protected");
response = client.execute(get);
entity = response.getEntity();
String content = EntityUtils.toString(entity);
At this point the 'entity' I get back from the website is "error":"Unauthorized Access."
You'll notice that I have a 'Credentials' instance being passed to the HttpClient and I'm also putting the user name & password in the HttpPost entity. I tried each of these approaches separately and they both returned the "error":"Unauthorized Access." result.
I've tried the DefaultHttpClient, which uses a single thread connection manager, as well as 'ThreadSafeClientConnManager' and neither worked.
first try to login using this url (copy the url to textpad or something first - then edit it):
https://www.centraldispatch.com/login?uri=%2Fprotected%2F&Username=XXX&Password=YYY
Just replace the XXX and YYY with your real user/pass - make sure it works.
Then use:
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(1);
nameValuePairs.add(new BasicNameValuePair("Username","Your username"));
nameValuePairs.add(new BasicNameValuePair("Password","Your password"));
post.setEntity(new UrlEncodedFormEntity(nameValuePairs));
HttpResponse response = client.execute(post);
BufferedReader rd = new BufferedReader(new InputStreamReader(
response.getEntity().getContent()));
String line = "";
while ((line = rd.readLine()) != null) {
System.out.println(line);
}
Did you set the User-Agent filed?Like that:
get.setHeader("Content-Type", "text/html");
get.setHeader("User-Agent","Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.0; .NET CLR 1.1.4322; .NET CLR 2.0.50215;)");
get.setHeader("Accept-Charset", Chareset+";q=0.7,*;q=0.7");//"utf-8;q=0.7,*;q=0.7");
And maybe you should get the login page firstly,to use the cookie.
If all this don't work,you shloud use some tools like firebug+firefox to track the network process,and emu them step by step.That should work.
Websites check some fields,I think this is definitely the reason.