HttpURLConnection POST response gets lost when server takes longer to respond - android

I'm having trouble catching a response to a POST request to server, when the server takes a bit longer to respond (when it is passed a bigger JSONObject).
When we call a GET method with a longer response time, there is no problem. When we call a POST and pass a relatively small JSONObject, the method registers a response.
The method is being called from an AsyncTask via new Task().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR).
When triggered from Postman, the response returns after 155 seconds, but it arrives. On the other hand, when triggered from the app, the code does nothing and ultimately tiggers a SocketTimeoutException.(For whatever reason, we have a timeout(connection and read timeout) set to 10 minutes) The code snippet for the service method is below. I'd appreciate any hints.
public static JSONObject requestWebService(String serviceUrl, JSONObject jsonObject) throws Exception {
private static final int CONNECTION_TIMEOUT = 1000 * 600;
private static final int DATARETREIVAL_TIMEOUT = 1000 * 600
HttpURLConnection urlConnection = null;
try {
URL urlToRequest;
String message;
urlToRequest = new URL(serviceUrl);
urlConnection = (HttpURLConnection) urlToRequest.openConnection();
urlConnection.setConnectTimeout(CONNECTION_TIMEOUT);
urlConnection.setReadTimeout(DATARETREIVAL_TIMEOUT);
if (jsonObject != null) {
urlConnection.setDoInput(true);
urlConnection.setDoOutput(true);
urlConnection.setRequestMethod("POST");
urlConnection.setRequestProperty("Content-Type", "application/json");
message = jsonObject.toString();
OutputStream os = new BufferedOutputStream(urlConnection.getOutputStream());
os.write(message.getBytes());
os.flush();
os.close();
} else {
urlConnection.setRequestMethod("GET");
}
int statusCode = urlConnection.getResponseCode();
if (statusCode == HttpURLConnection.HTTP_UNAUTHORIZED) {
throw new Exception("Acces unauthorized " + statusCode + ".");
} else if (statusCode != HttpURLConnection.HTTP_OK) {
throw new Exception("Server unavailable " + statusCode + ".");
}
return new JSONObject(ReplicationClient.convertInputStreamToString(urlConnection.getInputStream()));
} catch (MalformedURLException e) {
fileLogger.error(logHeader + e.getMessage(), e);
throw new Exception("Error " + e.getMessage(), e);
} catch (SocketTimeoutException e) {
fileLogger.error(logHeader + e.getMessage(), e);
throw new Exception("Error " + e.getMessage(), e);
} catch (IOException e) {
fileLogger.error(logHeader + e.getMessage(), e);
throw new Exception("Error " + e.getMessage(), e);
} catch (JSONException e) {
fileLogger.error(logHeader + e.getMessage(), e);
throw new Exception("Error " + e.getMessage(), e);
} catch (Exception e) {
fileLogger.error(logHeader + e.getMessage(), e);
throw new Exception("Error " + e.getMessage(), e);
} finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
}
}

after a second thought i have a theory
i will explain in details
but first try this code for writing data:
remove this from your code:
OutputStream os = new BufferedOutputStream(urlConnection.getOutputStream());
os.write(message.getBytes());
os.flush();
os.close();
use this:
OutputStream os = urlConnection.getOutputStream();
os.write( message.getBytes());
os.close();
if this works, then i will edit this answer and explain more.
This answer did not help as per the OP comment.
I am keeping this in case i found something else, otherwise, i will delete it later.

Related

OkHttpClient connection leak warning from HttpURLConnection

I'm using HttpURLConnection to retrieve some configuration from a server. It works fine but for some reason I'm getting the following warning in the logcat:
OkHttpClient: A connection to ... was leaked. Did you forget to close a response body?
As pointed out in this question, Android is using OkHttp internally in HttpUrlConnection. What am I doing to cause this warning?
Here is the code I'm using:
HttpURLConnection connection = null;
OutputStream outputStream = null;
String result;
try {
URL url = new URL(CONFIG_URL);
connection = (HttpURLConnection) url.openConnection();
connection.setReadTimeout(READ_TIMEOUT_MILLI);
connection.setConnectTimeout(CONNECT_TIMEOUT_MILLI);
connection.setRequestMethod(REQUEST_METHOD);
connection.setDoInput(true);
connection.addRequestProperty("Content-Type", "application/json");
connection.addRequestProperty("Accept", "application/json");
outputStream = connection.getOutputStream();
try (DataOutputStream wr = new DataOutputStream(outputStream)) {
wr.write(data.toString().getBytes(STRING_ENCODING));
wr.flush();
wr.close();
int responseCode = connection.getResponseCode();
if (responseCode != HttpsURLConnection.HTTP_OK) {
Log.e(TAG, "HTTP error code: " + responseCode);
return;
}
try (InputStream stream = connection.getInputStream()) {
if (stream != null) {
result = readStream(stream, READ_STREAM_MAX_LENGTH_CHARS);
//...
connection.disconnect();
}
} catch (Throwable e) {
Log.e(TAG, "run: failed to parse server response: " +e.getMessage());
}
}
} catch (Exception e) {
Log.e(TAG, "HttpSendTask: failed to send configuration request " + data +": " +e.getMessage());
} finally {
if (outputStream != null) {
try {
outputStream.flush();
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (connection != null) {
connection.disconnect();
}
}
Closing the inputstream of the connection solved my problem.
Try to close it in the finally block :
connection.getInputStream().close()

End of File Exception

Good day.
I have a problem with my NodeJS server.
I have an android app that gets information from MySQL database thru HttpUrlConnection every 30 seconds. The app and my server are working fine. But after about (not sure) 10 minutes or 20? my server does nothing and in my Logcat it says that my app throws EOFException
can someone help me fix this?
this image shows the app is working fine
and my server
but after sometime
server became this
this is my codes in getting info from mysql nodejs server
protected String doInBackground(String... arg0) {
HttpURLConnection connection = null;
HttpURLConnection connection1 = null;
String json = (String) arg0[0];
System.setProperty("http.keepAlive", "false");
try {
URL u = new URL("http://"+ MainActivity.ipadd +"/getmessage");
connection = (HttpURLConnection) u.openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Connection", "close");
connection.setRequestProperty("Content-Type","application/json");
//connection.setConnectTimeout(10000);
//connection.setReadTimeout(15000);
if (json != null) {
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setUseCaches(false);
Log.i("message", "To send : " + json);
byte[] outputInBytes = json.getBytes("UTF-8");
OutputStream os = connection.getOutputStream();
os.write( outputInBytes );
os.close();
os.flush();
}
//Connect to the server
connection.connect();
int status = connection.getResponseCode();
String staRes = connection.getResponseMessage().toString();
Log.i("HTTP Client", "HTTP status code : " + status + " " + staRes);
switch (status) {
case 200:
case 201:
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
sb = new StringBuilder();
String line;
while ((line = bufferedReader.readLine()) != null) {
sb.append(line + "\n");
}
bufferedReader.close();
Log.i("HTTP Client", "Response : " + sb.toString());
//return received string
holds.setRespone(sb.toString());
jo = new JSONObject(sb.toString());
jof = new JSONObject();
String tmp = jo.optString("mess");
String tmpp = jo.optString("cp");
String reff = jo.optString("ref");
boolean tmppp = false;
//jof.put("ref", jo.opt("ref"));
if(tmp.contains("err_code_01")){
tmppp = sendSMSMessage(tmpp, "Your MESSAGE was rejected. It contains wrong format.\nTrace Number:" + reff + "\nDo not reply.");
Log.v("sent message", "Your MESSAGE was rejected. It contains wrong format.");
} else if(tmp.contains("err_code_03")){
tmppp = sendSMSMessage(tmpp, "Your MESSAGE was rejected. It contains wrong position format.\nTrace Number:" + reff + "\nDo not reply.");
Log.v("sent message", "Your MESSAGE was rejected. It contains wrong position format.");
} else if(tmp.contains("err_code_04")){
tmppp = sendSMSMessage(tmpp, "Your MESSAGE was rejected. It contains wrong candidate-position format.\nTrace Number:" + reff + "\nDo not reply.");
Log.v("sent message", "Your MESSAGE was rejected. It contains wrong candidate-position format.");
} else if(tmp.contains("err_code_05")){
tmppp = sendSMSMessage(tmpp, "Your MESSAGE was rejected. It contains wrong vote count format.\nTrace Number:" + reff + "\nDo not reply.");
Log.v("sent message", "Your MESSAGE was rejected. It contains wrong vote count format.");
} else if(tmp.contains("success")){
tmppp = sendSMSMessage(tmpp, "Your MESSAGE was accepted.\nTrace Number:" + reff + "\nDo not reply.");
Log.v("sent message", "Your MESSAGE was accepted.");
}
return sb.toString();
}
} catch (MalformedURLException ex) {
Log.e("HTTP Client", "Error in HTTP Connection(Malformed URL) " + ex);
} catch (IOException ex) {
Log.e("HTTP Client", "Error in HTTP Connection(IO Exception) " + ex);
} catch (Exception ex) {
Log.e("HTTP Client", "Error in HTTP Connection(Exception) " + ex);
} finally {
//if (connection != null) {
//try {
connection.disconnect();
//} catch (Exception ex) {
// Log.e("HTTP Client", "Error in HTTP Connection " + ex.toString());
//}
//}
}
return null;
}
and for calling from MainActivity.class
final Handler handlerr = new Handler();
runnableGet = new Runnable(){
#Override
public void run() {
try{
gett = new GetMessageFromServer();
gett.execute(tmpp.toString());
}catch (Exception e){
//err here
Log.v("err", "runnable: " + e.toString());
} finally{
handlerr.postDelayed(runnableGet, 30000);
}
}
};
handlerr.postDelayed(runnableGet, 30000);

Verification of http post

I'm using the following code to post to a Google Form. If the HTTP response is not successful then the record is not marked as sent from the sqlite database and is resent during the next sync operation. The problem is I see frequent double posts because a response is not received even though the post was successful.
Is there a better way to confirm the post without creating double posts to the form?
Thanks for your help.
private Boolean performPost(String...data){
prefs = UserData.getPrefs(mContext);
spreadsheetKey = prefs.getString(UserData.PREF_SPREADSHEET_KEY,"");
ArrayList<BasicNameValuePair> results = new ArrayList<BasicNameValuePair>();
HttpPost post = new HttpPost("https://spreadsheets.google.com/spreadsheet/formResponse?hl=en_US&formkey=" + spreadsheetKey);
int counter = 0;
for (String s : data){
results.add(new BasicNameValuePair("entry." + counter + ".single", s));
counter ++;
}
try {
post.setEntity(new UrlEncodedFormEntity(results));
} catch (UnsupportedEncodingException e) {
// Auto-generated catch block
Log.e(TAG, "An error has occurred", e);
}
try {
//client.execute(post);
HttpResponse response = client.execute(post);
StatusLine statusLine = response.getStatusLine();
returnCode = statusLine.getStatusCode();
Log.d(TAG, statusLine+ "\n"+ returnCode + " " + String.valueOf(post.getEntity()));
response.getEntity().consumeContent();
} catch (ClientProtocolException e) {
// Auto-generated catch block
Log.e(TAG, "client protocol exception", e);
} catch (IOException e) {
// Auto-generated catch block
Log.e(TAG, "io exception", e);
}
if (returnCode == 200){
return true;
}else{
resultTxt = SYNC_UNSUCCESSFUL_HTTP_ERROR;
Log.e(TAG,"post unsuccessful, http code :" + String.valueOf(returnCode));
sendBroadcast();
return false;
}
}

android HttpURLConnection wont desconnect?

aim using HttpURLConnection inside AsyncTask when i cancel AsyncTask and request abort or cancel the connection the AsyncTask stoped ok but HttpURLConnection still sending request and return with the values from the server
how i can make HttpURLConnection full stop cancel all requests or abort the request ?
this is the code i use
public static String post_string(String url, String urlParameters) throws IOException
{
HttpURLConnection conn = null;
try {
conn = (HttpURLConnection) new URL(url).openConnection();
} catch (MalformedURLException e) {
Log.e(Logger, "MalformedURLException While Creating URL Connection - " + e.getMessage());
throw e;
} catch (IOException e) {
Log.e(Logger, "IOException While Creating URL Connection - " + e.getMessage());
throw e;
}
conn.setDoOutput(true);
conn.addRequestProperty("User-Agent", "Mozilla/5.0");
conn.setRequestProperty("Accept-Charset", "UTF-8");
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
//if has Post inputs
conn.setRequestProperty("Content-Length", Integer.toString(urlParameters.length()));
OutputStream os = null;
System.setProperty("http.keepAlive", "false");
try {
os = conn.getOutputStream();
} catch (IOException e) {
Log.e(Logger, "IOException While Creating URL OutputStream - " + e.getMessage());
throw e;
}
try {
os.write(urlParameters.toString().getBytes());
} catch (IOException e) {
Log.e(Logger, "IOException While writting URL OutputStream - " + e.getMessage());
throw e;
}
InputStream in = null;
try {
in = conn.getInputStream();
} catch (IOException e) {
Log.e(Logger, "IOException While Creating URL InputStream - " + e.getMessage());
throw e;
}
String output = null;
try {
output = slurp(in);
} catch (IOException e) {
Log.e(Logger, "IOException While Reading URL OutputStream - " + e.getMessage());
throw e;
} finally {
try {
os.close();
in.close();
} catch (IOException e) {
Log.e(Logger, "IOException While Closing URL Output and Input Stream - " + e.getMessage());
}
}
conn.disconnect();
Log.i("Server output " , output);
return output;
}
private static String slurp(InputStream in) throws IOException
{
StringBuffer out = new StringBuffer();
byte[] b = new byte[4096];
for (int n; (n = in.read(b)) != -1;) {
out.append(new String(b, 0, n));
}
return out.toString();
}
and this is what i use to abort connection
conn.disconnect();
any advice how to abort ?
When you stop your AsyncTask like mTask.cancel(true); just call conn.disconnect();

Very slow retrieval on android with 3G connection. Not with HSDPA or WiFi or on emulator

This is a bit of a complicated question as I do not know the exact problem. The main issue is that it takes a very long to get a very small package of data from our REST server from our Android app. I will describe it in detail and hope you can help me.
Problem
Data retrieval is fast enough (+/- 100ms) when:
Connected with WiFi
Connected with HSDPA
Running on Android Emulator with network settings (delay and speed) set to GPRS
However, when I use a phone on a location with bad connection (3G instead of HSDPA) calling the services can take up to 4s (current timeout on the AsyncTask).
Android
This is the code used to communicate with the services:
/**
* Get json string from service
*
* #param urlString url of service
* #return json result from service
*/
private String callService(String urlString) {
InputStream in = null;
HttpURLConnection c = null;
Scanner s = null;
String json = null;
try {
URL url = new URL(urlString);
Log.i(getClass().getName() + ".callService()", "start calling service: " + url);
long start = java.lang.System.currentTimeMillis();
try {
setAuthentication();
c = (HttpURLConnection) url.openConnection();
c.connect();
in = new BufferedInputStream(c.getInputStream());
s = new Scanner(in);
s.useDelimiter("\\A");
json = s.next();
} catch (IOException e) {
Log.e(getClass().getName() + ".callService()", "error: " + e.getMessage(), e);
}
Log.i(getClass().getName() + ".callService()", "complete calling service: (" + (System.currentTimeMillis() - start) + " ms) " + url);
return json;
} catch (Exception e) {
Log.e(getClass().getName() + ".callService()", "error: " + e.getMessage(), e);
} finally {
if (s != null) {
s.close();
}
if (in != null) {
try {
in.close();
} catch (IOException e) {
Log.e(getClass().getName() + ".callService()", "error: " + e.getMessage(), e);
}
}
if (c != null) {
c.disconnect();
}
}
return json;
}
I have tried several ways to call this, but currently this is done using an AsyncTask:
/**
* Retrieve json from service
*
* #param url url of service
* #return json
*/
public String getJsonFromServiceBasic(String url) {
ServiceTask task = new ServiceTask();
try {
return task.execute(url).get(4000, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
Log.e(getClass().toString() + " getJsonFromServiceBasic(" + url + ")", " interrupt exception: " + e.getMessage(), e);
} catch (ExecutionException e) {
Log.e(getClass().toString() + " getJsonFromServiceBasic(" + url + ")", " execution exception: " + e.getMessage(), e);
} catch (TimeoutException e) {
task.cancel(true);
Log.e(getClass().toString() + " getJsonFromServiceBasic(" + url + ")", " timeout exception: " + e.getMessage(), e);
} catch (Exception e) {
Log.e(getClass().toString() + " getJsonFromServiceBasic(" + url + ")", " timeout exception: " + e.getMessage(), e);
}
return null;
}
/**
* AsyncTask way of calling service
*/
class ServiceTask extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... urls) {
String json = callService(urls[0]);
return json;
}
}
AndroidManifest.xml:
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="16"/>
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
Services
I do not think this is the issue, as it works fast enough with HSDPA, but I am not sure.
Restlet services on tomcat7 behind a proxy. We're using a ChallengeAuthenticator for authentication.
I have solved this problem by switching to Apache's HttpClient.
I am not sure why this is a solution as Google suggests using the HttpURLConnection, but for me this works.
Using this method instead of the callService method will solve my troubles with slow internet access.
private String callServiceClient(String urlString) {
String json = null;
HttpParams httpParams = new BasicHttpParams();
int connection_Timeout = 5000;
HttpConnectionParams.setConnectionTimeout(httpParams, connection_Timeout);
HttpConnectionParams.setSoTimeout(httpParams, connection_Timeout);
DefaultHttpClient httpClient = new DefaultHttpClient(httpParams);
httpClient.getCredentialsProvider().setCredentials(new AuthScope(null, -1),
new UsernamePasswordCredentials(user, password));
HttpGet httpget = new HttpGet(urlString);
// Execute the request
HttpResponse response;
try {
response = httpClient.execute(httpget);
// Examine the response status
StatusLine responseCode = response.getStatusLine();
Log.i(getClass() + ".callServiceClient()", "responsecode: " + responseCode);
if (responseCode.getStatusCode() != HttpStatus.SC_OK) {
return json;
}
// Get hold of the response entity
HttpEntity entity = response.getEntity();
// If the response does not enclose an entity, there is no need
// to worry about connection release
if (entity != null) {
// A Simple JSON Response Read
InputStream instream = entity.getContent();
json = convertStreamToString(instream);
// now you have the string representation of the HTML request
instream.close();
}
} catch (ClientProtocolException e) {
} catch (IOException e) {
e.printStackTrace();
}
return json;
}

Categories

Resources