Android DefaultHTTPConnection with Keep-Alive does not reuse TCP connection - android

I am trying to reuse HTTP connections with Keep Alive. The server supports Keep Alive, I send the Connection: Keep-Alive HTTP headers and still the connection is FIN (initiated by the Android client) right after the response is received. Some help would be appreciated.
Here some code:
DefaultHttpClient client = new DefaultHttpClient();
client.setKeepAliveStrategy(new DefaultConnectionKeepAliveStrategy());
client.setReuseStrategy(new DefaultConnectionReuseStrategy());
HttpParams params = client.getParams();
ClientConnectionManager mgr = client.getConnectionManager();
client = new DefaultHttpClient(new ThreadSafeClientConnManager(params, mgr.getSchemeRegistry()), params);
HttpPost post = new HttpPost(URL);
post.setHeader("Connection","Keep-Alive");
ByteArrayEntity entity = new ByteArrayEntity(requestBundle.postString().getBytes());
entity.setContentType("application/xml");
post.setEntity(entity);
HttpResponse response = client.execute(post);
When I check the HTTP request headers I see these:
Connection: Keep-Alive\r\n
Content-Length: 459\r\n
Content-Type: application/xml\r\n
Host: xxx.yyy.com\r\n
User-Agent: Apache-HttpClient/UNAVAILABLE (java 1.4)\r\n
In the HTTP response headers I see these:
HTTP/1.1 200 OK\r\n
Content-Type: application/xml\r\n
Content-Length: 8049\r\n
Date: Tue, 22 Jan 2013 03:14:40 GMT\r\n
Server: lighttpd/1.4.31\r\n
Looking at the responses and other TCP packets going over the line, it is clear that the Android client initiates a FIN based on some HTTP client settings that I am not aware of, which are not caused by the Keep-Alive settings on the server (the HTTP response does not contain header "Connection: close").
Please enlighten me!
Cheers,
Andrej

Related

android : Invalid authorisation header in http get response

I have tried all possible ways to get correct JSON response from the below microsoft health API url. But its always giving me the "Invalid Authorisation Request" in the JSON response. I have tried Base64 encoding of authorisation token also but its not responding. I don't know where i am going wrong ?
String authToken="EwCgAvF0BAAUkWhN6f8bO0+g89MA1fmZueWyRkQAAfO43zeEeKVHsQJ5DiKwK62uBH2Xxh5mkV9t0EnExHELbz3u/qeS0uTqOUL4dyc3QwDikXQvNwFXWyK7sj6ChM3NrIF9L+7mI0ecmBme8IcghJ+kU+4SxHWZkOrshA8g5XW+KliOJbKvu4bus+JiMYxwKnqkLW6hkVxGQ1EHf0HzkHTNnWMbr1T4vNWJos7ITalOorV455MGekOvhEaFETrma9lQfos0RPRbDhdaKJiNFxUYQCvVywlbxRm96AOHlm/Be7GKYgF+vyktNs4dPgPz2l9MlzSGSE0IXtamSCiCaUocLDQ9yMY+jxKA4VPqhvbr1z3rc7fMk/wJvYebxVsDZgAACEzG05vV/JrAcAGHT5EeXaixNgTOW+S7CMcp3qpJtcl6MKveXA1e3fgvSQPCHnsy9nDoWYMgk4Uv6UkMbirkyzlG2JMFVpLg9PJE6sHIO0BZlkMb/DWMudrEsR3dwz00H/zAru9u6jMHnrbb44C/1z5lyXgwB3jItd/SWmRUdCBu3rF8IBXglAeyHxH+Mj5Zt2l+2rqly0p2sSqoUwgi49kThIggSlmod932fLWATHx5Lx3BN/wGfWU9XQplphPwYQvBsRnwv+gcZi9eK07aDIcdGhcp9J1fwCkjnBTZw+f0mDOyEfUSCyD0pnRXwz5CYDVN94TfFgZdnFAwi5wslKNUOYh6QBAJzaSXS/nj376FsORdEA1mUgowb/I2npitlr7+NTN6S+qWMdpEuiOVDVydi3L0H+xXKOaagzrels7bN7RpK0C+/kUqLfFrg8SeXxinqd+qhADu+56pRJnh8Sn3qdx/FmTQ/iGSYnrMMlT6SRDUjNVFoS3F540B";
HttpClient client = new DefaultHttpClient();
HttpGet request = new HttpGet();
request.setURI(new URI("https://api.microsofthealth.net/v1/me/Summaries/Daily?startTime=" + startTime + "&endTime=" + endTime));
String authString = "Bearer " + authToken;
request.addHeader("Authorization", authString);
response = client.execute(request);
String json_string = EntityUtils.toString(response.getEntity());
I think you should check the access token again to make sure it's valid. Because I use the new token in your question, reponse still 401.
GET https://api.microsofthealth.net/v1/me/Profile/
Authorization: bearer EwCgAvF0BAAUkWhN6f8bO0+g89MA1fmZueWyRkQAAfO43zeEeKVHsQJ5DiKwK62uBH2Xxh5mkV9t0EnExHELbz3u/qeS0uTqOUL4dyc3QwDikXQvNwFXWyK7sj6ChM3NrIF9L+7mI0ecmBme8IcghJ+kU+4SxHWZkOrshA8g5XW+KliOJbKvu4bus+JiMYxwKnqkLW6hkVxGQ1EHf0HzkHTNnWMbr1T4vNWJos7ITalOorV455MGekOvhEaFETrma9lQfos0RPRbDhdaKJiNFxUYQCvVywlbxRm96AOHlm/Be7GKYgF+vyktNs4dPgPz2l9MlzSGSE0IXtamSCiCaUocLDQ9yMY+jxKA4VPqhvbr1z3rc7fMk/wJvYebxVsDZgAACEzG05vV/JrAcAGHT5EeXaixNgTOW+S7CMcp3qpJtcl6MKveXA1e3fgvSQPCHnsy9nDoWYMgk4Uv6UkMbirkyzlG2JMFVpLg9PJE6sHIO0BZlkMb/DWMudrEsR3dwz00H/zAru9u6jMHnrbb44C/1z5lyXgwB3jItd/SWmRUdCBu3rF8IBXglAeyHxH+Mj5Zt2l+2rqly0p2sSqoUwgi49kThIggSlmod932fLWATHx5Lx3BN/wGfWU9XQplphPwYQvBsRnwv+gcZi9eK07aDIcdGhcp9J1fwCkjnBTZw+f0mDOyEfUSCyD0pnRXwz5CYDVN94TfFgZdnFAwi5wslKNUOYh6QBAJzaSXS/nj376FsORdEA1mUgowb/I2npitlr7+NTN6S+qWMdpEuiOVDVydi3L0H+xXKOaagzrels7bN7RpK0C+/kUqLfFrg8SeXxinqd+qhADu+56pRJnh8Sn3qdx/FmTQ/iGSYnrMMlT6SRDUjNVFoS3F540B
-- response --
401 Unauthorized
Cache-Control: no-cache
Pragma: no-cache
Expires: -1
Server: Microsoft-IIS/8.5
WWW-Authenticate: Bearer realm="mshealth" error="invalid_token"
X-AspNet-Version: 4.0.30319
AppEx-Activity-Id: 7c22cdab-5307-4b62-b81b-42e1315d9b1b
x-powered-by: ASP.NET
Date: Mon, 31 Aug 2015 07:04:00 GMT
Content-Length: 0

About CURL Request

I have to use CURL request to parse an API link using android application.In the response i get an id and username as output.But,I have to display a token value from that API.That token is displayed on Linux machine while running curl.I didn't get the token value in windows machine.I used the code like this:
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost("http://moneyplayer.herokuapp.com/users.json");
JSONObject json_one,json;
json_one = new JSONObject();
json =new JSONObject();
json.put("password","userPwd");
json.put("username","userEmail");
json_one.put("user",json);
Log.v("JSON Response is",""+json_one);
StringEntity se = new StringEntity(json_one.toString());
se.setContentType(new BasicHeader(HTTP.CONTENT_TYPE, "application/json"));
httppost.setEntity(se);
httppost.setHeader("Content-type","application/json");
// Execute HTTP Post Request
HttpResponse response = httpclient.execute(httppost);
String responseStr = EntityUtils.toString(response.getEntity());
Log.v("Response String Value is",""+responseStr);
In Linux machine the output is displayed like this:
{"id":37,"username":"testing123#1234.com"}
HTTP/1.1 200 O4 Cache-Control:max-age=0, private, must-revalidate
Content-Type:application /json;
charset=utf-8 Date: Mon, 17 Mar 2014 15:33:51 GMT
Etag:"a8979713bed4432cb624cb404df16a53"
Set-Cookie:
remember_token=BAhbCGkqSSIlMTZkYmE4ZDhhZTA2YzI2OWQwZjM2Y2ZjZjNmY2YyZGUGOgZFRjA%3D--d29db574adf7a4df8671eb75f43166101b81ef65; path=/; expires=Fri, 17-Mar-2034 15:33:51 GMT
Set-Cookie:
_live_local_web_session=BAh7B0kiCmZsYXNoBjoGRVRvOiVBY3Rpb25EaXNwYXRjaDo6Rmxhc2g6OkZsYXNoSGFzaAk6CkB1c2VkbzoIU2V0BjoKQGhhc2h7BjoOc3VjY2Vzc2VzVDoMQGNsb3NlZEY6DUBmbGFzaGVzewY7ClsGSSIiU3VjY2Vzc2Z1bGx5IGNyZWF0ZWQgcHJvZmlsZS4GOwBUOglAbm93bzokQWN0aW9uRGlzcGF0Y2g6OkZsYXNoOj

Android: HTTP POST response - 401

I have faced with one problem - returning 401 error msg when you already signed in and trying to get access to another secured pages. The mystic of this problem for me is that I can get access to another secured pages after you are signed in if check it via Firefox RestCLient or via iOS app but cannot get access via Chrome Advanced Rest Client and Android app. However, content-type and other necessary params are set the same in both web tools and apps. I have tried to set different auth headers with encoded login:pass but it doesnt help and it doesnt need because it should work without it, I think(at least FF and iOS app work without this header). What`s gonna be wrong?
Response headers of Chrome:
401 Unauthorized
Loading time:
29
Request headers
Content-Type: application/x-www-form-urlencoded
Response headers
Date: Mon, 04 Mar 2013 10:01:02 GMT
Server: Apache/2.2.20 (Ubuntu)
X-Powered-By: PHP/5.3.6-13ubuntu3.9
Set-Cookie: peachy=qg3mjvchjh1oionqlhhv0jrn71; path=/
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Pragma: no-cache
Vary: Accept-Encoding
Content-Length: 96
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: text/html; charset=utf-8
Response headers of Firefox:
Status Code: 200 OK
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Connection: Keep-Alive
Content-Length: 202
Content-Type: application/json
Date: Mon, 04 Mar 2013 09:51:09 GMT
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Keep-Alive: timeout=5, max=100
Pragma: no-cache
Server: Apache/2.2.20 (Ubuntu)
X-Powered-By: PHP/5.3.6-13ubuntu3.9
That is my peace of Restful code in Android app:
public String serverRequest(int action, Bundle params) {
if (action == 0) {
if (Const.DEBUG_ENABLED)
Log.e(TAG, "You did not pass action.");
return "You did not pass action.";
}
try {
HttpRequestBase request = null;
HttpPost postRequest = null;
switch (action) {
case SIGN_IN:
request = new HttpPost();
request.setURI(new URI(SIGNIN_URL));
request.setHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
postRequest = (HttpPost) request;
if (params != null) {
UrlEncodedFormEntity formEntity = new
UrlEncodedFormEntity(paramsToList(params));
postRequest.setEntity(formEntity);
}
break;
case SIGN_OUT:
request = new HttpPost();
request.setURI(new URI(SIGNOUT_URL));
request.setHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
break;
case BANK_CARD_VERIFY:
request = new HttpPost();
request.setURI(new URI(BANK_CARD_VERIFY_URL));
request.setHeader("Content-Type", "application/x-www-form-urlencoded; charset=utf-8");
postRequest = (HttpPost) request;
if (params != null) {
UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(paramsToList(params));
postRequest.setEntity(formEntity);
}
break;
}
if (request != null) {
DefaultHttpClient client = new DefaultHttpClient();
if (Const.DEBUG_ENABLED)
Log.d(TAG, "Executing request: " + actionToString(action) + ": " + urlToString(action));
HttpResponse response = client.execute(request);
StatusLine responseStatus = response.getStatusLine();
int statusCode = responseStatus != null ? responseStatus.getStatusCode() : 0;
Log.d(TAG, "Status code: " + statusCode);
}
}
(sign in and sign out are public, bank_verify is secured page. Android app has the same response headers like chrome). It seems there is something problem with session or something else but I`m not sure exactly.
EDIT:
It seems I have found what`s the problem here. In Android app I create a new HttpCLient object due to it all old data is losed. But another question - how to make this HttpCLient reusable?
Problem found. I reuse httpClient everytime in spite of that to use only one which has all session data everytime. Just implement if statement to check if I have already httpclient object then you it otherwise create a new.

Android socket & HTTP response headers

The funny thing is: I may have accidentally found the solution for Is it possible to send HTTP request using plain socket connection and receive response without headers?. I hope I'm overlooking something.
Anyway, I'm connecting to a web server, send a HTTP request, receive the response and close the connection. The actual HTTP conversation (tcpdump on the server side) looks like this:
GET /blah.php?param1=test1t&param2=test2 HTTP/1.0
HTTP/1.1 200 OK
Date: Sat, 22 Sep 2012 10:16:46 GMT
Server: Apache/2.2.17 (Ubuntu)
X-Powered-By: PHP/5.3.5-1ubuntu7.8
Vary: Accept-Encoding
Content-Length: 17
Connection: close
Content-Type: text/html
<pre>173364</pre>
Cool. It works... so far. Now this is the code. The string szRetval contains only "<pre>173364</pre>".
Socket s = new Socket("1.2.3.4", 80);
//DataInputStream in = new DataInputStream(s.getInputStream());
BufferedReader bin = new BufferedReader(new InputStreamReader(s.getInputStream()));
DataOutputStream out = new DataOutputStream(s.getOutputStream());
out.writeBytes(szRequest);
String szRetval = "";
String szLine = "";
while((szLine=bin.readLine())!=null) {
szRetval += szLine;
}
s.close();
return szRetval;
As you can see from the code sample, I've already switched from DataInputStream to BufferedReader. It makes no difference, so I guess this has to do with the Socket class itself.
Why o why are the http response headers not returned by a (raw) socket??
Android 2.3.3, Network I/O in AsyncTask, not using proxy.

Android HttpPost failes - server receives null query string parameter

I have a simple WCF web service on my machine which I have developed to serve Android and IOS devices.
The service has a single method as following :
[OperationContract]
[WebInvoke(RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Wrapped, UriTemplate = "/?message={message}")]
string ServiceMessage(string message);
I have 3 clients , one .NET test client using HttpWebRequest which works fine , one IOS client which works fine and one Android client which I have developed with the HttpPost and HttpClient classes that fails.
Using Fiddler reverse proxy I have debugged the output of the .net client :
POST http://127.0.0.1:8888/Service1.svc/?message=_|JSON MESSAGE BODY|_HTTP/1.1
Content-Type: application/json; charset=utf-8
Host: 127.0.0.1:8888
Content-Length: 338
Expect: 100-continue
Connection: Keep-Alive
_|JSON MESSAGE BODY|_
On the other hand , this is the output of the Android HTTP Post :
POST http://10.0.2.2:8888/Service1.svc/ HTTP/1.1
Content-Type: application/json; charset=utf-8
Content-Length: 139
Host: 10.0.2.2:8888
Connection: Keep-Alive
User-Agent: Apache-HttpClient/UNAVAILABLE (java 1.4)
Expect: 100-Continue
message=_|JSON MESSAGE BODY|_
As you can see , .Net puts the message parameter on the Post at the top and does not
put the message variable name at the bottom while Android does not put the message body at the Post at the top and does put the message variable name at the bottom.
This is my Android post code ,
HttpPost httpPost = new HttpPost(url);
String messageBody = "message=" + jsonMessageParameter;
StringEntity entity = new StringEntity(messageBody);
httpPost.setEntity(entity);
httpPost.setHeader("Content-Type", "application/json; charset=utf-8");
HttpResponse response = hc.execute(httpPost);
InputStream content = response.getEntity().getContent();
String json = ConvertStreamToString(content);
When calling with this code , the server method is called but the message method parameter is null.
I tried playing with the Uri.Builder class to also make the android post put the message at the header , but doesnt quite work.
If can someone help me out here , I am stuck on this for hours over hours.
Thank you in advance ,
James
EDIT :
I changed the Android code to :
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(1);
nameValuePairs.add(new BasicNameValuePair("message", jsonMessageParameter));
HttpPost httpPost = new HttpPost(url);
UrlEncodedFormEntity urlEncodedFromEntity = new UrlEncodedFormEntity(
nameValuePairs);
urlEncodedFromEntity.setContentType(new BasicHeader("Content-Type",
"application/json; charset=utf-8"));
httpPost.setEntity(urlEncodedFromEntity);
InputStream postStream = httpPost.getEntity().getContent();
String postOutput = ConvertStreamToString(postStream);
HttpResponse response = hc.execute(httpPost);
InputStream content = response.getEntity().getContent();
String json = ConvertStreamToString(content);
But still the Fiddler monitoring is as following :
POST http://10.0.2.2:8888/Service1.svc/ HTTP/1.1
Content-Length: 189
Content-Type: application/json; charset=utf-8
Host: 10.0.2.2:8888
Connection: Keep-Alive
User-Agent: Apache-HttpClient/UNAVAILABLE (java 1.4)
Expect: 100-Continue
message=_|MESSAGE_JSON|_
There a number of points here.
First, you specifically added message= to your Android POST body:
String messageBody = "message=" + jsonMessageParameter;
This can be also problematic since you specified Content-Type: application/json but by adding message= you are not providing a valid JSON object.
Second, why does the .Net implementation replicate the JSON object both as parameter in the URL and in the body? This looks strange and very uncommon for a POST request, and can cause problem if your JSON object makes the URL exceed the maximum URL length.
So I would try removing message= in the body and removing the JSON object as a URL parameter, since servers processing POSTs should read the body and not the URL.
HttpPost is for posting, afaik.
String url;
input = url + URLEncoder.encode(messageBody, "utf-8");
HttpClient httpclient = new DefaultHttpClient();
HttpGet httpget = new HttpGet(input);
InputStream stream = httpclient.execute(httpget).getEntity().getContent();
String s = streamToString(stream);
JSONObject jObject = new JSONObject(s);
This very exact code (plus some try/catch) works for me for querying GoogleBooks, probably you can adapt it to your service with little effort?
Best regards.

Categories

Resources