Posting data to web service from Android doesn't get sent - android

I am working on a project which was working fine before Christmas but suddenly doesn't without any changes being made.
The project involves a C++ which listens on a particular port and listens to post requests in a REST API to process the data and store in a database.
It consists of an Android library which gathers information and then sends this as an HTTP POST to the rest API on the C++ app.
The C++ app prints out the HTTP response that was received straight from receiving it on the socket before any processing done. First the android app has to send an initalisation request to the C++ app, the C++ prints the request and shows post data was sent, and successfully initalises and sends a response back to android including a session cookie. I then re-use the HttpClient within Android to post the next request which contains a fair amount of data but this request doesn't work.
When stepping through the android library I can see the post values have been successfully set and are being used to perform the HTTP request, however, the C++ app only receives the HTTP headers, not any post data.
If in the second request, I replace the post data with only a couple of post fields, the C++ then sees the post data, so it looks like the DefaultHTTPClient in Android isn't sending the post data if the post data is quite large.
Below is how I am posting the data in Android
if (httpClient == null)
{
//AndroidHttpClient client = new AndroidHttpClient();
httpClient = new DefaultHttpClient();
}
HttpParams httpParams = httpClient.getParams();
HttpConnectionParams.setConnectionTimeout(httpParams, 3000);
HttpConnectionParams.setSoTimeout(httpParams, 3000);
HttpPost httpPost = new HttpPost(serverURL);
//httpPost.setHeader("Content-Type", "application/x-www-form-urlencoded");
httpPost.setHeader("Authorisation-Token", authorisationToken);
httpPost.setHeader("Connection", "close");
//httpPost.setHeader("Cookie", "SESSIONID=zd8d5n3kucysl4idug1911m7ye");
httpPost.setEntity(new UrlEncodedFormEntity(postData, "UTF-8"));
String headers = "";
responseHandler = new ResponseHandler<String>()
{
#Override
public String handleResponse(HttpResponse httpResponse) throws ClientProtocolException, IOException
{
return EntityUtils.toString(httpResponse.getEntity());
}
};
responseBody = httpClient.execute(httpPost, responseHandler);
Log.d("Response", responseBody);
//httpClient = null;
if (responseBody != null && !responseBody.isEmpty())
{
httpClient.getConnectionManager().closeIdleConnections(0, TimeUnit.NANOSECONDS);
JSONObject jsonObject = new JSONObject(responseBody);
return jsonObject;
}
else
{
httpClient.getConnectionManager().closeIdleConnections(0, TimeUnit.NANOSECONDS);
return null;
}
As an example the post data is being created as follows:
postData = new ArrayList<>();
postData.add(new BasicNameValuePair("Test", "Item 1"));
postData.add(new BasicNameValuePair("Test 2", "Item 2"));
and the above is passed in to the execute command of the ASyncTask.
Below is how I am receiving the data on the socket from C++
string LinuxSocket::receiveDataOnSocket(int *socket)
{
string receiveData = "";
char * temp = NULL;
int bytesReceived = 0;
do
{
bytesReceived = recv(*socket, this->buffer, this->bufferLength, 0);
if (bytesReceived < 0)
{
stringstream logstream;
logstream << "Failed to read data on socket. Error: " << strerror(bytesReceived);
this->bitsLibrary->writeToLog(logstream.str(), "LinuxSocket", "receiveDataOnSocket");
this->closeSocket(socket);
throw SocketException(strerror(bytesReceived));
}
//If we got here then we should be able to get some data
temp = new char[bytesReceived + 1];
strncpy(temp, this->buffer, bytesReceived);
temp[bytesReceived] = '\0';
receiveData.append(temp);
delete[] temp;
temp = NULL;
memset(this->buffer, 0, this->bufferLength);
} while (bytesReceived == this->bufferLength);
return receiveData;
}
The post data that I am sending is a follows:
POST /crash HTTP/1.1
User-Agent: My Android User Agent
Authorisation-Token: DlzSIkx4ro*OatHCV6epfWY0F
Connection: close
Content-Length: 1231
Content-Type: application/x-www-form-urlencoded
Host: 192.168.1.123:500
Cookie: SESSIONID=6rc5q1db0z8lupe5uij5ten3mw
Cookie2: $Version=1
Severity=Critical&DeviceID=36e85611db16c7fa&VersionName=1.5&DeviceType=Android&ROMBuild=sdk_gphone_x86-userdebug+8.0.0+OSR1.170901.056+4497355+dev-keys&KernelVersion=3.18.81%2B&DeviceBrand=google&DeviceModel=Android+SDK+built+for+x86&APILevel=26&ScreenResolution=1080+x+1776&Locale=English&MobileNetwork=Android&CrashType=Handled&ExceptionType=java.lang.Exception&Stacktrace=java.lang.Exception%3A+Standard+Exception+been+thrown%0A%09at+com.MyCompany.MyApp.MainActivity%242.onClick%28MainActivity.java%3A67%29%0A%09at+android.view.View.performClick%28View.java%3A6256%29%0A%09at+android.view.View%24PerformClick.run%28View.java%3A24701%29%0A%09at+android.os.Handler.handleCallback%28Handler.java%3A789%29%0A%09at+android.os.Handler.dispatchMessage%28Handler.java%3A98%29%0A%09at+android.os.Looper.loop%28Looper.java%3A164%29%0A%09at+android.app.ActivityThread.main%28ActivityThread.java%3A6541%29%0A%09at+java.lang.reflect.Method.invoke%28Native+Method%29%0A%09at+com.android.internal.os.Zygote%24MethodAndArgsCaller.run%28Zygote.java%3A240%29%0A%09at+com.android.internal.os.ZygoteInit.main%28ZygoteInit.java%3A767%29%0A&CustomProperty=%7B%22Test+Non+Json+Property%22%3A%22Here+is+my+value%22%7D&AppID=15869700
As an example the post data that successfully works is a follows:
POST /initialise HTTP/1.1
Authorisation-Token: DlzSIkx4ro*OatHCV6epfWY0F
Connection: close
Content-Length: 48
Content-Type: application/x-www-form-urlencoded
Host: 192.168.1.123:500
User-Agent: My Android User Agent
ApplicationID=15869700&DeviceID=36e85611db16c7fa
I've also captured the request from Android and sent it from a Rest API Test Client Insomnia.Rest and sent this to the Rest API and the C++ successfully sees all of the post data, so it looks like the problem is the Android library won't send post data if its of a certain size.
Is this the case, and how can I get round this?

I found the issue with this, there were two separate things that I've done to resolve this.
The issue with no post data at all being sent, I changed from the org.apache.DefaultHTTPClient to the OkHTTPClient. From looking at Google it looks like the apache version has been deprecated and the OkHTTPClient is the preferred HTTP client anyway. This then sent some post data but not everything. This brings me to the second fix (I don't think the issue was actually with the apache client, I think it was my C++ receiving data on the socket).
The second fix I did was to change my receiveDataOnSocket function in the C++ app.
When I've worked on socket to socket communication then normally if the buffer is full, then usually I can expect to receive more data, if the buffer is only partly full, then all data is sent and I return the received data.
It looks like HTTP doesn't necessarily send as much as the buffer on receiving socket can handle, I've therefore changed my receive data on socket to process the data as its being received to look for the Content-Length header, and the length of the body that I may have, then on each subsequent recv call, I increment the current body count by the receivedBytes count and if the body length is equal to the content length I stop receiving data on the socket and return the HTTP request.

Related

How to use HTTP POST with "application/octet-stream" in Android? (Microsoft Cognitive Video)

I want to use the Video Cognitive Service in Android.
The sample that Microsoft provided is used in C#.
The video function is sending an URL to the server,
So I think it is possible using HTTP POST to send an URL in Android.
http://ppt.cc/V1piA
The problem I met is that I don't know the URL format in "application/octet-stream", and I didn't see the example on the Microsoft website.
Is it possible using HTTP POST in Android to upload a downloaded video to the server, and I can get the analysis result from the server?
If possible, what is the format of the HTTP POST to send request to the server?
Thanks.
You may try something like this to send image files for cognitive-services face detect.
Using org.apache.httpcomponents::httpclient :
#Test
public void testSendBinary() throws MalformedURLException {
File picfile = new File("app/sampledata/my_file.jpeg");
if (!picfile.exists()) throw new AssertionError();
HttpClient httpclient = HttpClients.createDefault();
try {
URIBuilder builder = new URIBuilder("https://westcentralus.api.cognitive.microsoft.com/face/v1.0/detect");
builder.setParameter("returnFaceId", "true");
builder.setParameter("returnFaceLandmarks", "false");
URI uri = builder.build();
HttpPost request = new HttpPost(uri);
request.setHeader("Content-Type", "application/octet-stream");
request.setHeader("Ocp-Apim-Subscription-Key", "***");
// Request body
request.setEntity(new FileEntity(picfile));
HttpResponse response = httpclient.execute(request);
HttpEntity entity = response.getEntity();
if (entity != null) {
System.out.println(EntityUtils.toString(entity));
}
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
HTTP POST refers to the HTTP method 'POST', application/octet-stream refers to the media type - in this case a stream of application specific octets or bytes.
This is, unfortunately, very subjective as the mechanism for uploading content via HTTP action may be preferred one way or another. Suffice it to say, you will create an InputStream of your content, format a POST request using the mechanism of your choosing:
straight Java
HTTPClient
Making sure to set the content-type of the POST to application/octet-stream.
After performing the post, consult your API documentation for expected return types.

Send token with HTTP POST from android to cakephp

i am sending data from an android device to my cakephp website through HTTP Post in json object ..like this
HttpPost post = new HttpPost("https://www.mywebtest.com/test");
and then i decode the json and extract the data like this
if ($this->request->isPost()){
$json = $this->request->data('json');
$data = json_decode($json, TRUE);
but at the moment i am not checking that whether the http post or data is coming from my android app or someone else .so if someone knows the url he can do something malicious ..because at times now the url which i have written in httpPost when i typed this url in my browser there is nothing is shown on the browser.. i want to display some kind of error or 404 page if some one typed the url in browser.. Essentially, you can say i am creating with CakePHP is an API, What i want to do is secure the API so only my app can execute requests.so i want to implement some type of authentication .. doing some research i come up to a solution that pass another parameter as a secret token from android app and then check token from my webapp and then extract data .. i dont know how can i pass another parameter in httppost and then check it on my webpage .. and also if that possible i want to randomly generate the token and encrypt it on every request and then decrypt it through key in webapp whenever the data is posting from android to webapp.. if someone has done before this or have an idea then please share code or any link.
Create a JsonObject for parameters,
JSONObject parametersList = new JSONObject();
put your parameters into that JSONObject
parametersList.put("testID", 123);
int androidValue = 231231231; // a identifer or password your choice.
parametersList.put("androidValue", androidValue);
and add list to your HttpPost
HttpPost request = new HttpPost("https://www.mywebtest.com/test");
request.setHeader(HTTP.CONTENT_TYPE, "application/json; charset=utf-8");
request.setEntity(new StringEntity(parameters.toString(), HTTP.UTF_8));
On the php side;
<?php
$postdata = $HTTP_RAW_POST_DATA;
$data = json_decode($postdata);
$id = $data->testID;
$androidValue = $data->androidValue;
if(androidValue == 231231231)
{
$json = "{d:[{sample1:'".$id."',sample2:'value12'}]}";
$response = $_GET["callback"] . $json;
echo $response;
}
else
{
// send failed data
}
?>
And this how to get respond on android side
HttpResponse response = client.execute(request);
final int statusCode = response.getStatusLine().getStatusCode();
final String jsonResponse = EntityUtils.toString(response.getEntity());
if (statusCode != HttpStatus.SC_OK) {
Log.w(TAG, "Error in web request: " + statusCode);
Log.w(TAG, jsonResponse);
return null;
} else {
Log.i(TAG, jsonResponse);
return jsonResponse;
}
I hope this will help.
Try with RequestHandler isMobile().
You will get true, if request is from mobile phone.
http://book.cakephp.org/2.0/en/core-libraries/components/request-handling.html#RequestHandlerComponent::isMobile

Android Http Client Caching

In my android application I am trying to cache the response of Http Client. I am testing this task using facebook graph api and have the following url: https://graph.facebook.com/riz.ahmed.52
For the first time I get the "first_name" and display it. Then I change the First Name of my facebook profile and call the same link again. I am expecting to get the old/cached "first_name" but I get the updated one. The console always shows the "The response came from an upstream server" message when I call the url.
My code for Http Client is as follows:
CacheConfig cacheConfig = new CacheConfig();
cacheConfig.setMaxCacheEntries(1000);
cacheConfig.setMaxObjectSizeBytes(8192);
//HttpClient httpclient = new CachingHttpClient(new DefaultHttpClient(), cacheConfig);
DefaultHttpClient httpclient = new DefaultHttpClient();
HttpContext localContext = new BasicHttpContext();
// Updated code [START]
httpclient.addResponseInterceptor(new HttpResponseInterceptor() {
public void process(
final HttpResponse response,
final HttpContext context) throws HttpException, IOException {
response.removeHeader(response.getFirstHeader("Pragma"));
response.removeHeader(response.getFirstHeader("Expires"));
}
});
// Updated code [END]
HttpGet httpget = new HttpGet(url);
// Execute HTTP Get Request
HttpResponse response = httpclient.execute(httpget, localContext);
HttpEntity entity = response.getEntity();
String res = EntityUtils.getContentCharSet(entity);
CacheResponseStatus responseStatus = (CacheResponseStatus) localContext.getAttribute(
CachingHttpClient.CACHE_RESPONSE_STATUS);
switch (responseStatus) {
case CACHE_HIT:
System.out.println("A response was generated from the cache with no requests " +
"sent upstream");
break;
case CACHE_MODULE_RESPONSE:
System.out.println("The response was generated directly by the caching module");
break;
case CACHE_MISS:
System.out.println("The response came from an upstream server");
break;
case VALIDATED:
System.out.println("The response was generated from the cache after validating " +
"the entry with the origin server");
break;
}
I am using Android 2.3.3. Please let me know what I am missing here
The page you are loading specifies a Expires:Sat, 01 Jan 2000 00:00:00 GMT header, i.e. it's always considered stale and must always be re-fetched.
Edit:
Also returns a Pragma: no-cache apparently. Basically, it's telling your HTTP client to never cache this page. You may be able to remove these headers with a HttpResponseInterceptor if you're dead-set on caching the response.
#2 Edit:
Using http-clientcache-4.2.jar is going to be problematic as it is not completely compatible with the version of the HTTP client packaged with the Android SDK - you're going to get NoClassDefFoundErrors and similar nonsense when using it.
However - if you "build-your-own" by downloading the source for clientcache-4.2 and strip out any unfulfilled references (such as refactoring the package name of the commons logging) & killing of all the annotations sprinkled throughout the code (etc.) you can probably get a working version. If you do, this worked:
class MakeCacheable implements HttpResponseInterceptor {
public static MakeCacheable INSTANCE = new MakeCacheable();
public void process(HttpResponse resp, HttpContext ctx) throws HttpException, IOException {
resp.removeHeaders("Expires");
resp.removeHeaders("Pragma");
resp.removeHeaders("Cache-Control");
}
}
Injected into the DefaultHttpClient used by the CachingHttpClient like so:
DefaultHttpClient realClient = new DefaultHttpClient();
realClient.addResponseInterceptor(MakeCacheable.INSTANCE, 0); // This goes first
CachingHttpClient httpClient = new CachingHttpClient(realClient, cacheConfig);
If an entry is cached or not is decided by the ResponseCachingPolicy which unfortunately is a final in the CachingHttpClient, but looking through it will show all the headers that need to go to make an un-cacheable entry cacheable.

sending json object to HTTP server in android

I am sending a JSON object to a HTTP Server by using the following code.
The main thing is that I have to send Boolean values also.
public void getServerData() throws JSONException, ClientProtocolException, IOException {
ArrayList<String> stringData = new ArrayList<String>();
DefaultHttpClient httpClient = new DefaultHttpClient();
ResponseHandler <String> resonseHandler = new BasicResponseHandler();
HttpPost postMethod = new HttpPost("http://consulting.for-the.biz/TicketMasterDev/TicketService.svc/SaveCustomer");
JSONObject json = new JSONObject();
json.put("AlertEmail",true);
json.put("APIKey","abc123456789");
json.put("Id",0);
json.put("Phone",number.getText().toString());
json.put("Name",name.getText().toString());
json.put("Email",email.getText().toString());
json.put("AlertPhone",false);
postMethod.setEntity(new ByteArrayEntity(json.toString().getBytes("UTF8")));
String response = httpClient.execute(postMethod,resonseHandler);
Log.e("response :", response);
}
but its showing the exception in the line
String response = httpClient.execute(postMethod,resonseHandler);
as
org.apache.http.client.HttpResponseException: Bad Request
can any one help me.
The Bad Request is the server saying that it doesn't like something in your POST.
The only obvious problem that I can see is that you're not telling the server that you're sending it JSON, so you may need to set a Content-Type header to indicate that the body is application/json:
postMethod.setHeader( "Content-Type", "application/json" );
If that doesn't work, you may need to look at the server logs to see why it doesn't like your POST.
If you don't have direct access to the server logs, then you need to liaise with the owner of the server to try and debug things. It could be that the format of your JSON is slightly wrong, there's a required field missing, or some other such problem.
If you can't get access use to the owner of the server, the you could try using a packet sniffer, such as WireShark, to capture packets both from your app, and from a successful POST and compare the two to try and work out what is different. This can be a little bit like finding a needle in a haystack though, particularly for large bodies.
If you can't get an example of a successful POST, then you're pretty well stuffed, as you have no point of reference.
This may be non-technical, but
String response = httpClient.execute(postMethod,-->resonseHandler);
There is a spelling mistake in variable name here, use responseHandler(defined above)

Android Send data back to server

How would one go about sending data back to server, from an android application?
I've already tried using HttpPost and posted back to a RESTful WCF service, but I couldnt get that to work (I've already created a SO question about this, without finding the solution..) - No matter what I do I keep getting 405 Method not allowed or the 400 Bad Request.. :(
I'm not asking for full code example necessarily.. just a pointer in a direction, which can enable me to send data back to a server.
It is important that the user should not have to allow or dismiss the transfer.. it should happen under the covers, so to speak
Thanks in advance
Services is the way to go. REST (I recommend this one on Android), or SOAP based. There're loads of tutorials on getting an android app communicate a service, even with .net / wcf ones.
Tho you can always just open raw sockets and send data with some custom protocol.
Edit:
Here's the doInBackground part of my asynctask handling http post communication, maybe that'll help:
protected String doInBackground(String... req) {
Log.d(TAG, "Message to send: "+req[0]);
HttpPost p = new HttpPost(url);
try{
p.setEntity(new StringEntity(req[0], "UTF8"));
}catch(Exception e){
e.printStackTrace();
}
p.setHeader("Content-type", "application/json");
String response = "";
try{
HttpResponse resp = hc.execute(p, localContext);
InputStream is = resp.getEntity().getContent();
response = convertStreamToString(is);
Log.d("Response", "Response is " + response);
} catch (Exception e){
e.printStackTrace();
}
return response;
}

Categories

Resources