Android HttpPut Has No Body, Despite Setting the Entity - android

I'm trying to PUT some XML to a server, but the gist of it is that no matter what I do, HttpPut simply won't put anything in the Http body. The server always comes back saying that the body is missing, and looking at it through Wireshark, nothing is there! Here's the code I'm using to set up and run the request:
HttpPut putRequest = new HttpPut(urlString]);
StringEntity stringEntity = new StringEntity(xmlString, HTTP.ISO_8859_1);
stringEntity.setContentType("text/xml");
putRequest.setEntity(stringEntity);
putRequest.addHeader("Host", formatUrlForHostHeader(broadsoftUrl));
putRequest.addHeader("Authorization", authorizationString);
putRequest.addHeader("Content-Type", "text/xml");
putRequest.addHeader("Accept", "text/xml");
response = httpClient.execute(putRequest);
I'm not sure what else to include here. I tried it on 4.2 and 4.0.3. This code is running in the doInBackground of an AsyncTask. The response code I get is a 409 Conflict, and the body is the server's application-specific message, telling me the body is missing. I confirmed that it's missing with Wireshark.
EDIT:
An interesting note is that I ran the same code standalone on my desktop, and it worked. So, is there something up with the Android versions of HttpClient, or the system? I tried a few different API levels, too, just to check.
Any thoughts?
Thanks!

Alright, so the solution was to just give up on HttpPut and all that, and use HttpURLConnection. Here's how we ended up doing it:
URL url = new URL(theUrl);
HttpURLConnection httpCon = (HttpURLConnection) url.openConnection();
httpCon.setRequestProperty("Host", formatUrlForHostHeader(broadsoftUrl));
httpCon.setRequestProperty("Authorization", authorizationString);
httpCon.setRequestProperty("Content-Type", "text/xml; charset=ISO_8859_1");
httpCon.setRequestProperty("Accept", "text/xml");
httpCon.setDoInput(true);
httpCon.setDoOutput(true);
httpCon.setRequestMethod("PUT");
OutputStreamWriter out = new OutputStreamWriter(httpCon.getOutputStream(), "ISO_8859_1");
out.write(xmlData);
out.close();
if(httpCon.getErrorStream() == null) {
return "";
} else {
return "ERROR";
}
We didn't need to get the response from our PUT request, but you check if it failed by seeing if the error stream exists. If you wanted to get the response, you would do something like this:
StringWriter writer = new StringWriter();
IOUtils.copy(httpCon.getInputStream(), writer, encoding);
String responseString = writer.toString();
Of course, you would have to include Apache's IOTools in your app.

409 Conflict is usually an Edit Conflict error, usually associated with wikis, but it could be any type of conflict with the request.
http://en.wikipedia.org/wiki/List_of_HTTP_status_codes
http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
What type of data are you trying to post and is it possible that the host has existing data that cannot be changed?

Related

Pushbullet API via http in Android

How can I receive Pushbullet notes/images/profile details via API-Key on Android? My main problem is the SSL security in that point. (BTW: I'm pretty much a beginner in Android and only know the basics.)
The auth looks like this:
https://apikey#api.pushbullet.com/v2/users/me
I'm successfully requesting the content of a webpage (e.g. wikipedia.org) via
try {
URL url = new URL("https://www.wikipedia.org");
URLConnection urlConnection = url.openConnection();
InputStream in = urlConnection.getInputStream();
StringWriter writer = new StringWriter();
IOUtils.copy(in, writer);
theString = writer.toString();
textView.setText(theString);
} catch (Exception e) {
textView.setText("Error: "+e "String content: " +theString);
}
but when I'm requesting, for example, my profile details I'm always getting a
javaio FileNotFoundException
If you run your requests through https://www.runscope.com you can often see what the request is that your client is actually making (they have a free plan for trying it out).
If I had to guess I would say it's likely the authorization is not working correctly. Are you able to get that page using curl? It should look something like:
curl -u <apikey>: https://api.pushbullet.com/v2/users/me
Assuming that works, try something like
urlConnection.setRequestProperty("Authorization", "Bearer <apikey>");
or however it is you set headers on your HTTP requests. This is more explicit than relying on the https://password#domain url thing.

Http get pass parameters

Im new to Android development but Im trying to do an application for Opencart to allow users to enter in their own store to administrate it.
Lets go to the point. In order to get the information from the store i created a page where all the information is presented in XML, so the idea is that the user login, and then redirects to this page and with the http response, parse the xml and voilá!.
I have already the xml parser, but Im having some difficulties with the http connection. Let me explain a little bit more:
Basically, to log into any store, you need to go to www.example.com/admin (I will be using my testing online address to see if someone is able to help me), in this case http://www.onlineshop.davisanchezplaza.com/admin . Once we arrive to the page we arrive to the login system. The login system uses post to send the username: admin and password:admin and redirects to http://onlineshop.davidsanchezplaza.com/admin/index.php?route=common/login and once it verify your identity, it gives you a Token (here I start having some problems). http://onlineshop.davidsanchezplaza.com/admin/index.php?route=common/home&token=8e64583e003a4eedf54aa07cb3e48150 . Well, till here, im very okay, and actually developed an app that can do till here, actually i can "hardcode" read the token from the http response it sends me (what is actually not very good).
Here comes my first question: HOW TO GET FROM THE HTTPresponse the token value? (by now, as I said, I can only get the token by reading all the response, and if we find the string token=, take what comes next ... not good).
HttpClient httpClient = new DefaultHttpClient();
HttpConnectionParams.setConnectionTimeout(httpClient.getParams(), TIMEOUT_MS);
HttpConnectionParams.setSoTimeout(httpClient.getParams(), TIMEOUT_MS);
HttpPost httpPost = new HttpPost("http://onlineshop.davidsanchezplaza.com/admin/index.php?route=common/login");
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
nameValuePairs.add(new BasicNameValuePair("username", "admin"));
nameValuePairs.add(new BasicNameValuePair("password", "admin"));
try{
Log.d(DEBUG_TAG, "Try ");
httpPost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
HttpResponse response = httpClient.execute(httpPost);
BufferedReader br = new BufferedReader(new InputStreamReader(response.getEntity().getContent()), 8096);
Log.d(DEBUG_TAG, "br :" + br);
String line;
while ((line = br.readLine()) != null) {
Log.d(DEBUG_TAG, "br :" + line);
if(line.contains("token=")){
int index = line.indexOf("token=");
String aux = line.substring(index + "token=".length(), index + 32 + "token=".length());
token = aux; //Yes, I know, its not the best way.
break;
}
}
} catch (IOException e) {
Log.d(DEBUG_TAG, "Finally");
}
Second question, (and more important), now having the token (in the example 8e64583e003a4eedf54aa07cb3e48150), I need to go to the route android/home where is the xml information generated. (http://onlineshop.davidsanchezplaza.com/admin/index.php?route=android/home2&token=8e64583e003a4eedf54aa07cb3e48150). As I was reading, in httpget, we can either set the parameters, or directly send the url with the parameters already inside the url. Is in this step where it stops. Maybe is the internet connexion in China, maybe (most sure) im doing something wrong. Sometimes it just come the timeout connexion, others it just send me back to the login page.
Here is the code how i do (edit: I was a noob, and didnt create the httpclient to receive the answer, sorry!):
String s = "http://onlineshop.davidsanchezplaza.com/admin/index.php?route=common/home&token=";
String tot = s.concat(token);
HttpClient httpClient = new DefaultHttpClient();
HttpConnectionParams.setConnectionTimeout(httpClient.getParams(), TIMEOUT_MS);
HttpConnectionParams.setSoTimeout(httpClient.getParams(), TIMEOUT_MS);
HttpGet httpget = new HttpGet(tot);
try{
Log.d(DEBUG_TAG, "Try ");
HttpResponse response = httpClient.execute(httpget);
BufferedReader br = new BufferedReader(new InputStreamReader(response.getEntity().getContent()), 8096);
Log.d(DEBUG_TAG, "br :" + br);
} catch (IOException e) {
Log.d(DEBUG_TAG, "Finally");
}
I dont need someone to tell me how to do it, just need a little guidance to solve the issue, I really appreciate any comment or help you can offer, or extra documentation :).
As a bonus, if someone can give me further details about how can I test the http get, I will appreciate, I only know how to write it in the web browser, and works fine.
It's a while since I last did something for Android, but here is my advice:
for the login purpose from Android application into the OpenCart administration I recommend creating a new mobile login page, e.g. instead of accessing http://yourstore.com/admin/ which redirects You to http://.../admin/index.php?route=common/login create Your own action e.g. androidLogin() within this controller (admin/controller/common/login.php and You will access it directly via http://yourstore.com/admin/index.php?route=common/login/androidLogin. Why special action? Because the default login action redirects the user (using normal browser) to the home while setting the security token into the URL within the query string part. In Your own action You won't redirect but respond with XML containing this security token so that You can easily extract that token using Your XML parser.
I cannot address second problem exactly but from what I remember I was passing a query string in different way (now I cannot find any similar solution on the internet).
Here is my 5 cents for the second question :
After playing a bit with the browser I realized :
Set Cookies
Your request to ...?route=android/home2&token= seems to be rejected if you are missing cookies. That is, you probably need to extract cookies from first server response and set them for further requests either manually (via conn.setRequestProperty("Cookie", cookie); or using Android CookieManager
User agent
Some server may reject your request just because you are missing "User-Agent" property in request header. To be safe, you could set it to something like conn.setRequestProperty("User-Agent", "Mozilla/5.0");
Extra note - I suggest that you also handle redirects correctly, as for example when you POST your admin/admin credentials you get 302 response and redirected to ...?route=common/home page
Also, you don't need to set conn.setDoInput(true) for UrlConnection while doing GET request.
Hope that helps.
I don't see any catch statement for the try in the second question, this catch may have the info you need to know what's going on.
For the first question try to convert InputStreamReader to a String, and use the String for a
url constructor, with the url (or uri i'm not sure right now, and can't test it) object try .getQueryParameter("parameter").
For your second question when i tried to login using the token that you have provided, the web page replied with invalid token. Can you login with the token that you have provided? If not, try to get a new token. Maybe the token have expired.

Http Put Request

I am using the HttpPut to communicate with server in Android, the response code I am getting is 500.After talking with the server guy he said prepare the string like below and send.
{"key":"value","key":"value"}
now I am completely confused that where should i add this string in my request.
Please help me out .
I recently had to figure out a way to get my android app to communicate with a WCF service and update a particular record. At first this was really giving me a hard time figuring it out, mainly due to me not knowing enough about HTTP protocols, but I was able to create a PUT by using the following:
URL url = new URL("http://(...your service...).svc/(...your table name...)(...ID of record trying to update...)");
//--This code works for updating a record from the feed--
HttpPut httpPut = new HttpPut(url.toString());
JSONStringer json = new JSONStringer()
.object()
.key("your tables column name...").value("...updated value...")
.endObject();
StringEntity entity = new StringEntity(json.toString());
entity.setContentType("application/json;charset=UTF-8");//text/plain;charset=UTF-8
entity.setContentEncoding(new BasicHeader(HTTP.CONTENT_TYPE,"application/json;charset=UTF-8"));
httpPut.setEntity(entity);
// Send request to WCF service
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpResponse response = httpClient.execute(httpPut);
HttpEntity entity1 = response.getEntity();
if(entity1 != null&&(response.getStatusLine().getStatusCode()==201||response.getStatusLine().getStatusCode()==200))
{
//--just so that you can view the response, this is optional--
int sc = response.getStatusLine().getStatusCode();
String sl = response.getStatusLine().getReasonPhrase();
}
else
{
int sc = response.getStatusLine().getStatusCode();
String sl = response.getStatusLine().getReasonPhrase();
}
With this being said there is an easier option by using a library that will generate the update methods for you to allow for you to update a record without having to manually write the code like I did above. The 2 libraries that seem to be common are odata4j and restlet. Although I haven't been able to find a clear easy tutorial for odata4j there is one for restlet that is really nice: http://weblogs.asp.net/uruit/archive/2011/09/13/accessing-odata-from-android-using-restlet.aspx?CommentPosted=true#commentmessage
Error 500 is Internal Server error. Not sure if this answers your question but I personally encountered it when trying to send a data URI for an animated gif in a PUT request formatted in JSON but the data URI was too long. You may be sending too much information at once.

Android default charset when sending http post/put - Problems with special characters

I have configured the apache httpClient like so:
HttpProtocolParams.setContentCharset(httpParameters, "UTF-8");
HttpProtocolParams.setHttpElementCharset(httpParameters, "UTF-8");
I also include the http header "Content-Type: application/json; charset=UTF-8" for all http post and put requests.
I am trying to send http post/put requests with a json body that contains special characters (ie. chinese characters via the Google Pinyin keyboard, symbols, etc.) The characters appear as gibberish in the logs but I think this is because DDMS does not support UTF-8, as descibed in this issue.
The problem is when the server receives the request, it sometimes doesn't see the characters at all (especially the Chinese characters), or it becomes meaningless garbage when we retrieve it through a GET request.
I also tried putting 250 non-ascii characters in a single field because that particular field should be able to take up to 250 characters. However, it fails to validate at the server side which claims that the 250 character limit has been exceeded. 250 ASCII characters work just fine.
The server dudes claim that they support UTF-8. They even tried simulating a post request that contains Chinese characters, and the data was received by the server just fine. However, the guy (a Chinese guy) is using a Windows computer with the Chinese language pack installed (I think, because he can type Chinese characters on his keyboard).
I'm guessing that the charsets being used by the Android client and the server (made by Chinese guys btw) are not aligned. But I do not know which one is at fault since the server dudes claim that they support UTF-8, and our rest client is configured to support UTF-8.
This got me wondering on what charset Android uses by default on all text input, and if it can be changed to a different one programatically. I tried to find resources on how to do this on input widgets but I did not find anything useful.
Is there a way to set the charset for all input widgets in Android? Or maybe I missed something in the rest client configuration? Or maybe, just maybe, the server dudes are not using UTF-8 at their servers and used Windows charsets instead?
Apparently, I forgot to set the StringEntity's charset to UTF-8. These lines did the trick:
httpPut.setEntity(new StringEntity(body, HTTP.UTF_8));
httpPost.setEntity(new StringEntity(body, HTTP.UTF_8));
So, there are at least two levels to set the charset in the Android client when sending an http post with non-ascii characters.
The rest client itself itself
The StringEntity
UPDATE: As Samuel pointed out in the comments, the modern way to do it is to use a ContentType, like so:
final StringEntity se = new StringEntity(body, ContentType.APPLICATION_JSON);
httpPut.setEntity(se);
I know this post is a bit old but nevertheless here is a solution:
Here is my code for posting UTF-8 strings (it doesn't matter if they are xml soap or json) to a server. I tried it with cyrillic, hash values and some other special characters and it works like a charm. It is a compilation of many solutions I found through the forums.
HttpParams httpParameters = new BasicHttpParams();
HttpProtocolParams.setContentCharset(httpParameters, HTTP.UTF_8);
HttpProtocolParams.setHttpElementCharset(httpParameters, HTTP.UTF_8);
HttpClient client = new DefaultHttpClient(httpParameters);
client.getParams().setParameter("http.protocol.version", HttpVersion.HTTP_1_1);
client.getParams().setParameter("http.socket.timeout", new Integer(2000));
client.getParams().setParameter("http.protocol.content-charset", HTTP.UTF_8);
httpParameters.setBooleanParameter("http.protocol.expect-continue", false);
HttpPost request = new HttpPost("http://www.server.com/some_script.php?sid=" + String.valueOf(Math.random()));
request.getParams().setParameter("http.socket.timeout", new Integer(5000));
List<NameValuePair> postParameters = new ArrayList<NameValuePair>();
// you get this later in php with $_POST['value_name']
postParameters.add(new BasicNameValuePair("value_name", "value_val"));
UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(postParameters, HTTP.UTF_8);
request.setEntity(formEntity);
HttpResponse response = client.execute(request);
in = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
StringBuffer sb = new StringBuffer("");
String line = "";
String lineSeparator = System.getProperty("line.separator");
while ((line = in.readLine()) != null) {
sb.append(line);
sb.append(lineSeparator);
}
in.close();
String result = sb.toString();
I hope that someone will find this code helpful. :)
You should set charset of your string entity to UTF-8:
StringEntity stringEntity = new StringEntity(urlParameters, HTTP.UTF_8);
You can eliminate the server as the problem by using curl to send the same data.
If it works with curl use --trace to check the output.
Ensure you are sending the content body as bytes. Compare the HTTP request from Android with the output from the successful curl request.

Error HTTP/1.0 405 Method not Allowed

I want to make an Htttp Connection Here is my code
try
{
HttpClient client = new DefaultHttpClient();
HttpPost httpMethod = new HttpPost("http://www.google.co.in/");
String requestBody = "some text";
HttpMethod.setEntity(new StringEntity(requestBody));
HttpResponse response = client.execute(httpMethod);
textView.setText(response.getStatusLine().toString());
}
But i m unable to and get the "HTTP/1.0 405 Method not Allowed" error
I will be thankfull your help
It means that the requested URL does not accept the POST method. Try again with GET.
Perhaps you should try with a server that accepts POST requests. There's probably nothing wrong with your code, Google's front page just doesn't do POST.
One quick example of a server you could use I can think of is JSFiddle's echo feature. I'm sure they won't mind.

Categories

Resources