HttpPost: No "Set-Cookie" Header - android

I want to get the session cookie of a website. Unfortunately the "Set-Cookie"-Header doesn't show up.
Here's the code I've written:
"commands" is a String[][] and the whole code is wrapped by try/catch.
CookieStore cookieStore = new BasicCookieStore();
HttpContext localContext = new BasicHttpContext();
localContext.setAttribute(ClientContext.COOKIE_STORE,cookieStore);
HttpPost httppost = new HttpPost(url);
List<NameValuePair> nvps = new ArrayList<NameValuePair>(0);
for (int i=0;i<commands.length;++i)
nvps.add(new BasicNameValuePair(commands[i][0],commands[i][1]));
httppost.setEntity(new UrlEncodedFormEntity(nvps,HTTP.UTF_8));
HttpResponse response = httpclient.execute(httppost);
HttpEntity entity = response.getEntity();
Header[] headers = response.getAllHeaders();
List<Cookie> cookies = cookieStore.getCookies();
String data = EntityUtils.toString(entity);
My understanding of Http Communication tells me that there should be a "Set-Cookie" Header. The only Headers I get from response.getAllHeaders() are Connection:close, X-Powered-By:PHP/4.3.4 and Content-Type:text/html
There is a bit of javascript included in the returned data (response.getEntity()).
<script language = "javascript">
<!--
location.href="/index.php";
function SetCookie(name,value,expire,path){
document.cookie = name + "=" + escape(value) + ((path == null) ? "":(";path="+path))
}
var iad = 461180104
SetCookie("iad",iad,0,"/")
-->
</script>
As far as I understand this, this code is never executed because it's just a comment ?!
But as well this is probably the bit where the cookie should be created.
Any ideas?
UPDATE:
"Opera Mobile" is the only browser for Android I found which has no problem with cookies on this site. "Opera Mini", "Dolphin HD" and the Froyo Stock browser all fail. No Desktop browser has problems connecting. Is this a webkit issue? And if this is the case: how to avoid it?

Using Chrome's developer tools or Firebug, check the HTTP response for the "expires" parameter in the Set-Cookie header field. Make sure the time / date settings on the phone are set correctly. If the browser thinks the cookie is already expired, it won't store it.
If that doesn't work try using wireshark / tshark to grab a trace of the communication from your client, and compare it to a browser that's working the way you expect it to.
By the way, the comment delimiters around that bit of Javascript don't prevent the script from being run; they just prevent older (really old) browsers from trying to render the script in the document. That cookie ("iab") doesn't look like the cookie for authentication. There's likely an http-only cookie with a session identifier; you should be able to see it using the aforementioned Firebug / Dev tools.

Related

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.

Unexpected response to HTTP POST request in Android

I recently came across strange problem when sending / recieving data thru http POST request on Android.
I had difficulties with setting Fiddler to monitor the traffic between my Android app and server so I created simple web form to simulate the POST request.
<form action="http://www.my.server.org/my_script.php" method="POST">
<input name="deviceID" type="text" width=30> Device ID <br>
<input name="lang" type="text" width=30> Language (en / cs) <br>
<input name="lastUpdated" type="text" width=30> Last Updated (yyyy-MM-dd hh:mm) <br>
<button type="submit">Send</button>
</form>
When I send the request using this form, a response is delivered back with 200 OK status code and desired XML file.
I thought it would be equivalent to Java code I have in my Android app.
private static final String POST_PARAM_LAST_UPDATED = "lastUpdated";
private static final String POST_PARAM_DEVICE_ID = "deviceId";
private static final String POST_PARAM_LANG = "lang";
...
// Create a POST Header and add POST Parameters
HttpPost httpPost = new HttpPost(URL_ARTICLES);
List<NameValuePair> postParameters = new ArrayList<NameValuePair>(3);
postParameters.add(new BasicNameValuePair(POST_PARAM_DEVICE_ID, deviceId));
postParameters.add(new BasicNameValuePair(POST_PARAM_LANG, lang));
postParameters.add(new BasicNameValuePair(POST_PARAM_LAST_UPDATED, lastUpdated));
httpPost.setEntity(new UrlEncodedFormEntity(postParameters));
// Create new HttpClient and execute HTTP Post Request
HttpClient httpClient = new DefaultHttpClient();
HttpResponse response = httpClient.execute(httpPost);
// Get and parse the response
List<Article> parsedArticles = new ArrayList<Article>();
HttpEntity entity = response.getEntity();
if (entity != null) {
parsedArticles = Parser.parseArticles(entity.getContent());
}
However even when I put the same parameter values (as those I put in the web form), the response in this case is 204 NO CONTENT and no XML file obviously.
Can somebody here please tell me how come these two methods are not equivalent and the responses are different? Is it something with encoding or what am I missing?
I unfortunately don't have access to the server and I'm not able to debug Android outgoing and incoming data because Fiddler and my emulator / device connected to PC refused to cooperate.
And I also wondered if I should use AndroidHttpClient instead of DefaultHttpClient but I think it's not going to change anything in this case.
Thanks in advance!
Due to Maxims comment I found out what's wrong.
It was one stupid lower case letter in the POST_PARAM_DEVICE_ID constant. It's value was "deviceId" (and should be "deviceID" as in web form).
Well, my fellow developers, pay attention when defining String keys - it's case sensitive!

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.

EntityUtils reports NoApplicableCode exception for Android request

I am trying to retrieve a JSON file from a web service using the following URL. That works fine when I use a browser to send the HTTP request.
For the Android application I came up with the following code.
// Android request
String url = "http://data.wien.gv.at/daten/geoserver/ows?service=WFS" +
"&request=GetFeature&version=1.1.0&typeName=ogdwien:BAUMOGD" +
"&srsName=EPSG:4326&outputFormat=json" +
"&bbox=16.377681,48.211448,16.379829,48.21341,EPSG:4326" +
"&maxfeatures=10"
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost(url);
HttpResponse response = httpclient.execute(httppost);
HttpEntity entity = response.getEntity();
String result = EntityUtils.toString(entity);
Though, EntityUtils does not output a JSON file but this XML exception.
// Value of result
<?xml version="1.0" encoding="UTF-8"?>
<ows:ExceptionReport version="1.0.0"
xsi:schemaLocation="http://www.opengis.net/ows http://data.wien.gv.at/daten/geoserver/schemas/ows/1.0.0/owsExceptionReport.xsd"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ows="http://www.opengis.net/ows">
<ows:Exception exceptionCode="NoApplicableCode">
<ows:ExceptionText>java.io.EOFException: input contained no data
input contained no data</ows:ExceptionText>
</ows:Exception>
</ows:ExceptionReport>
I hope you can see what wents wrong ...
The HTML specifications technically define the difference between "GET" and "POST" so that former means that form data is to be encoded (by a browser) into a URL while the latter means that the form data is to appear within a message body. > [source]
Since you do encode the full request into the URL (request=GetFeature etc.) => use HttpGet instead.
Might even work imo with post since the url should still be transmitted to the server but the server would need to detect that the post request is actually a get request and behave accordingly.

Android: Example for using a cookie from HttpPost for HttpGet

I am able to use the example here: http://www.androidsnippets.org/snippets/36/index.html and successfully get the "HTTP/1.1 OK" response for a webesite I am sending the HttpPost along with the user credentials. However, I am unable to use an HttpGet to further browse other pages on this site.
Can anyone please let me know, what's going wrong. I am sorry - I am very new to Java.
My guess would be that when the website gets the Post and logs the user in, it sets cookies on the response to indicate that the user is logged in, and then requires those cookies on subsequent Get's.
You will need to do something like the following (this is borrowed from a bigger app so may not compile right out of the box)
DefaultHttpClient mHttpClient = new DefaultHttpClient();
BasicHttpContext mHttpContext = new BasicHttpContext();
CookieStore mCookieStore = new BasicCookieStore();
mHttpContext.setAttribute(ClientContext.COOKIE_STORE, mCookieStore);
This sets up a cookie store within the HTTP context, and you then use that context on Get's and Post's. For example...
HttpResponse response = mHttpClient.execute(mRequest, mHttpContext);
Under the covers the HTTP client will store cookies from responses, and add them to requests.

Categories

Resources