HttpClient not sending all cookies to restful api - java

I am calling a restful api using HttpClient 4.4.1, but it is not sending the cookies,
private CloseableHttpResponse call(String url, javax.servlet.http.HttpServletRequest httpServletRequest) {
HttpGet request = new HttpGet(url);
BasicHttpContext localContext = new BasicHttpContext();
CookieStore cookieStore = new BasicCookieStore();
javax.servlet.http.Cookie[] cookies = httpServletRequest.getCookies();
BasicClientCookie basicClientCookie = null;
if (cookies != null) {
for (int i = 0; i < cookies.length; i++) {
javax.servlet.http.Cookie cookie = cookies[i];
basicClientCookie = new BasicClientCookie(cookie.getName(), cookie.getValue());
basicClientCookie.setDomain(cookie.getDomain());
basicClientCookie.setPath("/");
basicClientCookie.setAttribute(ClientCookie.DOMAIN_ATTR, "true");
basicClientCookie.setVersion(0);
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.DAY_OF_YEAR, 100);
Date date = calendar.getTime();
basicClientCookie.setExpiryDate(date);
cookieStore.addCookie(basicClientCookie);
}
}
if (cookieStore.getCookies() != null) {
System.out.println("Cookies size " + cookieStore.getCookies().size());
}
localContext.setAttribute(HttpClientContext.COOKIE_STORE, cookieStore);
CloseableHttpClient httpClient = HttpClients.createDefault();
CloseableHttpResponse httpResponse = null;
try {
httpResponse = httpClient.execute(request, localContext);
} catch (IOException e) {
System.out.println("msg " + e.getMessage());
}
return httpResponse;
}
I can see it is only sending the last cookie which has been added. What am i missing? Please help.

The problem is for sure in the code inside the for loop because only the last added cookie is visible.
Try to debug the for loop either using debugger or by adding the system.out.println statement before the loop when you are getting cookies array from request, than inside the loop when you are creating basic client cookie and then before and after adding basic client cookie to cookiestore
As suggested in the comments you have also not added cookiestore to the context.
localContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore);
Another problem with the above code is
basicClientCookie.setDomain(cookie.getDomain());
cookie.getDomain() and url of the request can be different and as per the cookies behaviour they should be same then only cookies will send.So only cookies having same url will be send with the request

Related

Get response from the web service for HttpResponse

In my application, the User can upload images to a PHP server, the iOS version is working 100%, the Android version used for this tutorial to upload image:
tutorial example
And the function I'm using is this:
public static String sendPost(String url, String imagePath)
throws IOException, ClientProtocolException {
HttpClient httpclient = new DefaultHttpClient();
httpclient.getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION,
HttpVersion.HTTP_1_1);
HttpPost httppost = new HttpPost(url);
File file = new File(imagePath);
MultipartEntity mpEntity = new MultipartEntity();
ContentBody cbFile = new FileBody(file, "image/jpeg");
mpEntity.addPart("userfile", cbFile);
httppost.setEntity(mpEntity);
//Log.e("executing request " + httppost.getRequestLine());
HttpResponse response = httpclient.execute(httppost);
HttpEntity resEntity = response.getEntity();
//Log.e(""+response.getStatusLine());
if (resEntity != null) {
//Log.e(EntityUtils.toString(resEntity));
}
if (resEntity != null) {
resEntity.consumeContent();
}
httpclient.getConnectionManager().shutdown();
return response.toString();
}
return response.toString(); get it in org.apache.http.message.BasicHttpResponse # 406dc148
But the return of the web service is the URL where the image was saved, I need to have a string in the return of the PHP server, rather than the return I mentioned above how can I have it?
I wanted something like this (HttpURLConnection):
HttpURLConnection conn;
...
String response= "";
Scanner inStream = new Scanner(conn.getInputStream());
while(inStream.hasNextLine())
response+=(inStream.nextLine());
Log.e("resp", response);
After one hour onsegui trying to get the response from the Web service as follows:
...
byte [] responseBody = httppost.getMethod().getBytes();
Log.e("RESPONSE BODY",""+(new String(responseBody)));
...
If you want the content returned by the HTTP server, you shouldn't do this:
if (resEntity != null) {
resEntity.consumeContent();
}
... because that says "throw away the content".
Try this if the response is of type String
ResponseHandler<String> responseHandler = new BasicResponseHandler();
HttpResponse httpResponse = httpClient.execute(post, new BasicHttpContext()); // new BasicHttpContext() not necessary
// verify connection response status using httpResponse.getStatusLine().getStatusCode() then
String response = responseHandler.handleResponse(httpResponse);
if(response != mull){
Log.e("Response : "+response);
}else{
// Handle exception
}
return response;

Apache HttpClient: Cannot retrieve cookies sent from the server in Android device

I am having a strange problem while using Apache HttpClient in an Android app.
My app needs to Login to a website and get some data and then logout.
My current code looks like this:
public class BlueClient {
private String hostUrl;
private DefaultHttpClient client;
private HttpContext localContext;
public BlueClient(String hostUrl,DefaultHttpClient httpClient,HttpContext localContext) {
this.hostUrl = hostUrl;
this.client = httpClient;
this.localContext = localContext;
}
public boolean doLogin(String userName,String password){
String url = getHostUrl()+"do_login";//loggin will set a session cookie
HttpPost post = new HttpPost(url);
try {
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
nameValuePairs.add(new BasicNameValuePair("username",userName));
nameValuePairs.add(new BasicNameValuePair("password",password));
post.setEntity(new UrlEncodedFormEntity(nameValuePairs));
HttpResponse response = client.execute(post,localContext);
//ok now if response is ok then return true
} catch (Exception e) {
}
return false;
}
public MyStuff getMyStuff(){
String url = getHostUrl()+"/getMyStuff/"; //this url requires authentication. the sesion cookie should do that
HttpGet get = new HttpGet(url);
try {
HttpResponse response = client.execute(get,localContext);
//ok get my stuff from response and return
} catch (Exception e) {
}
return null;
}
public boolean doLogout(){
String url = getHostUrl()+"do_logout";//it clears the cookie so the session is invalidated
HttpGet get = new HttpGet(url);
try {
HttpResponse response = client.execute(get,localContext);
//ok the cookie is cleared
}
} catch (Exception e) {
}
return false;
}
}
And when i call these function i do like this. It works in emulator but not in device
HttpContext context = new BasicHttpContext();
CookieStore cookieStore = new BasicCookieStore();
context.setAttribute(ClientContext.COOKIE_STORE,cookieStore);
DefaultHttpClient httpClient = new DefaultHttpClient();
BlueClient myClient = new BlueClient("http://myHost.com/",httpClient,context);
myClient.doLogin("user","pass");
// it should've printed the cookies set by the server but i get nothing here !
D.log(context.getAttribute(ClientContext.COOKIE_STORE));
// as this is another subsequesnt request it shoud carry the cookies back to the server but as the cookies are not set this function gives me nothig :-(
myClient.getMyStuff();
myClient.doLogout();
Can anyone please shed some light on this. Why its not working in the device?
Ah I finally found the problem!
My server runs on CodeIgniter. And CodeIgniter set the expiry date of the session cookie (ci_session) as Netscape cookie draft compliant. And the format is EEE, dd-MMM-yy HH:mm:ss zzz and Default CookiePoicy used by HttpClient is RFC_2109. So when the httpClient tries to parse the cookie data it fails on parsing the expiry date. I had to explicitly set the Cookie Policy and date format.
So my final code looks like this:
BasicHttpParams params = new BasicHttpParams();
String[] dateFormats = {"EEE, dd-MMM-yy HH:mm:ss zzz"};
params.setParameter(CookieSpecPNames.DATE_PATTERNS,Arrays.asList(dateFormats));
DefaultHttpClient httpClient = new DefaultHttpClient(params);
httpClient.getParams().setParameter(ClientPNames.COOKIE_POLICY,CookiePolicy.NETSCAPE);//explicitly set the cookie policy
HttpContext context = new BasicHttpContext();
CookieStore cookieStore = new BasicCookieStore();
context.setAttribute(ClientContext.COOKIE_STORE,cookieStore);
BlueClient myClient = new BlueClient("http://myHost.com/",httpClient,context);
myClient.doLogin("user","pass");
myClient.getMyStuff();//now i get my stuff !
myClient.doLogout();
Hope it saves someone's time :)

Http cookie store in Android

I am developing an Android client for the site with authorization. I have a post method. Example my code:
public void run() {
handler.sendMessage(Message.obtain(handler, HttpConnection.DID_START));
httpClient = new DefaultHttpClient();
HttpConnectionParams.setSoTimeout(httpClient.getParams(), 25000);
HttpResponse response = null;
try{
switch (method){
case POST:
HttpPost httpPost = new HttpPost(url);
httpPost.setHeaders(headers);
if (data != null) httpPost.setEntity(new StringEntity(data));
response = httpClient.execute(httpPost);
break;
}
processEntity(response);
}catch(Exception e){
handler.sendMessage(Message.obtain(handler, HttpConnection.DID_ERROR, e));
}
ConnectionManager.getInstanse().didComplete(this);
}
How to keep cookies?
You get your cookies from HttpResponse response:
Header[] mCookies = response.getHeaders("cookie");
and add them to your next request:
HttpClient httpClient = new DefaultHttpClient();
//parse name/value from mCookies[0]. If you have more than one cookie, a for cycle is needed.
CookieStore cookieStore = new BasicCookieStore();
Cookie cookie = new BasicClientCookie("name", "value");
cookieStore.addCookie(cookie);
HttpContext localContext = new BasicHttpContext();
localContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore);
HttpGet httpGet = new HttpGet("http://www.domain.com/");
HttpResponse response = httpClient.execute(httpGet, localContext);

Handling HttpClient Redirects

I'm POSTing some data to a server that is answering a 302 Moved Temporarily.
I want HttpClient to follow the redirect and automatically GET the new location, as I believe it's the default behaviour of HttpClient. However, I'm getting an exception and not following the redirect :(
Here's the relevant piece of code, any ideas will be appreciated:
HttpParams httpParams = new BasicHttpParams();
HttpClientParams.setRedirecting(httpParams, true);
SchemeRegistry schemeRegistry = registerFactories();
ClientConnectionManager clientConnectionManager = new ThreadSafeClientConnManager(httpParams, schemeRegistry);
HttpClient httpClient = new DefaultHttpClient(clientConnectionManager, httpParams)
HttpPost postRequest = new HttpPost(url);
postRequest.setHeader(HTTP.CONTENT_TYPE, contentType);
postRequest.setHeader(ACCEPT, contentType);
if (requestBodyString != null) {
postRequest.setEntity(new StringEntity(requestBodyString));
}
return httpClient.execute(postRequest, responseHandler);
For HttpClient 4.3:
HttpClient instance = HttpClientBuilder.create()
.setRedirectStrategy(new LaxRedirectStrategy()).build();
For HttpClient 4.2:
DefaultHttpClient client = new DefaultHttpClient();
client.setRedirectStrategy(new LaxRedirectStrategy());
For HttpClient < 4.2:
DefaultHttpClient client = new DefaultHttpClient();
client.setRedirectStrategy(new DefaultRedirectStrategy() {
/** Redirectable methods. */
private String[] REDIRECT_METHODS = new String[] {
HttpGet.METHOD_NAME, HttpPost.METHOD_NAME, HttpHead.METHOD_NAME
};
#Override
protected boolean isRedirectable(String method) {
for (String m : REDIRECT_METHODS) {
if (m.equalsIgnoreCase(method)) {
return true;
}
}
return false;
}
});
The default behaviour of HttpClient is compliant with the requirements of the HTTP specification (RFC 2616)
10.3.3 302 Found
...
If the 302 status code is received in response to a request other
than GET or HEAD, the user agent MUST NOT automatically redirect the
request unless it can be confirmed by the user, since this might
change the conditions under which the request was issued.
You can override the default behaviour of HttpClient by sub-classing DefaultRedirectStrategy and overriding its #isRedirected() method.
It seem http redirect is disable by default. I try to enable, it work but I'm still got error with my problem. But we still can handle redirection pragmatically. I think your problem can solve:
So old code:
AndroidHttpClient httpClient = AndroidHttpClient.newInstance("User-Agent");
HttpGet httpGet = new HttpGet(url);
HttpResponse httpResponse = httpClient.execute(httpGet);
long contentSize = httpResponse.getEntity().getContentLength();
This code will return contentSize = -1 if http redirect happend
And then I handle redirect by myself after trying enable default follow redirection
AndroidHttpClient client;
HttpGet httpGet;
HttpResponse response;
HttpHeader httpHeader;
private void handleHTTPRedirect(String url) throws IOException {
if (client != null)
client.close();
client = AndroidHttpClient.newInstance("User-Agent");
httpGet = new HttpGet(Network.encodeUrl(url));
response = client.execute(httpGet);
httpHeader = response.getHeaders("Location");
while (httpHeader.length > 0) {
client.close();
client = AndroidHttpClient.newInstance("User-Agent");
httpGet = new HttpGet(Network.encodeUrl(httpHeader[0].getValue()));
response = client.execute(httpGet);
httpHeader = response.getHeaders("Location");
}
}
In use
handleHTTPRedirect(url);
long contentSize = httpResponse.getEntity().getContentLength();
Thanks
Nguyen
My solution is using HttClient. I had to send the response back to the caller. This is my solution
CloseableHttpClient httpClient = HttpClients.custom()
.setRedirectStrategy(new LaxRedirectStrategy())
.build();
//this reads the input stream from POST
ServletInputStream str = request.getInputStream();
HttpPost httpPost = new HttpPost(path);
HttpEntity postParams = new InputStreamEntity(str);
httpPost.setEntity(postParams);
HttpResponse httpResponse = null ;
int responseCode = -1 ;
StringBuffer response = new StringBuffer();
try {
httpResponse = httpClient.execute(httpPost);
responseCode = httpResponse.getStatusLine().getStatusCode();
logger.info("POST Response Status:: {} for file {} ", responseCode, request.getQueryString());
//return httpResponse ;
BufferedReader reader = new BufferedReader(new InputStreamReader(
httpResponse.getEntity().getContent()));
String inputLine;
while ((inputLine = reader.readLine()) != null) {
response.append(inputLine);
}
reader.close();
logger.info(" Final Complete Response {} " + response.toString());
httpClient.close();
} catch (Exception e) {
logger.error("Exception ", e);
} finally {
IOUtils.closeQuietly(httpClient);
}
// Return the response back to caller
return new ResponseEntity<String>(response.toString(), HttpStatus.ACCEPTED);
For HttpClient v5, just use the below:
httpClient = HttpClientBuilder.create()
.setRedirectStrategy(new DefaultRedirectStrategy() {
#Override
public boolean isRedirected(HttpRequest request, HttpResponse response, HttpContext context)
throws ProtocolException {
return false;
}
}).build();

Java httpclient to log into website and download file - Session Problems!

I log on to a website using the POST method (httpclient from apache).
I let the HttpClient execute the HttpPost, let the connection manager release it and then I want to post a GET message that opens a php-URL file to download a pdf.
But all I get is the html file of a "session expired" page
(println: File: index_GT_neu.html?fehlermeldung=fehler_sessioncheck)
I was thinking that once i used the instance of HttpClient to log on at the site, I would be able to open another URL that is only available after log on. But appearently I was wrong.
Somebody could give me a hint?
Thanks in advance!
This is what my main looks like:
// prepare post method
HttpPost post = new HttpPost("http://epaper02.niedersachsen.com/epaper/index_GT_neu.html");
//prepare get method
HttpGet httpget = new HttpGet("http://epaper01.niedersachsen.com/epaper/getfile.php?pdf=0114_GTB_HP_01.pdf&zeitung=GT&ekZeitung=&Y=11&M=01&D=14&C=0");
// add parameters to the post method
List <NameValuePair> parameters = new ArrayList <NameValuePair>();
parameters.add(new BasicNameValuePair("username", "test"));
parameters.add(new BasicNameValuePair("passwort", "test"));
UrlEncodedFormEntity sendentity = new UrlEncodedFormEntity(parameters, HTTP.UTF_8);
post.setEntity(sendentity);
// create the client and execute the post method
HttpClient client = new DefaultHttpClient();
HttpResponse postResponse = client.execute(post);
//Output the Response from the POST
System.out.print(convertInputStreamToString(postResponse.getEntity().getContent()));
//releasing POST
EntityUtils.consume(postResponse.getEntity());
//Execute get
HttpContext context = new BasicHttpContext();
HttpResponse getResponse = client.execute(httpget, context);
System.out.println("Statusline: " + getResponse.getStatusLine());
if (getResponse.getStatusLine().getStatusCode() != HttpStatus.SC_OK)
throw new IOException(getResponse.getStatusLine().toString());
HttpUriRequest currentReq = (HttpUriRequest) context.getAttribute(ExecutionContext.HTTP_REQUEST);
String currentUrl = URLDecoder.decode(currentReq.getURI().toString(), "UTF-8");
int i = currentUrl.lastIndexOf('/');
String fileName = null;
if (i < 0) {
fileName = currentUrl;
} else {
fileName = currentUrl.substring(i + 1);
}
System.out.println("File: " + fileName);
//Create file
OutputStream os = new FileOutputStream( fileName);
InputStream is = getResponse.getEntity().getContent();
byte[] buf = new byte[4096];
int read;
while ((read = is.read(buf)) != -1) {
os.write(buf, 0, read);
}
os.close();
client.getConnectionManager().shutdown();
By default, DefaultHttpClient does not have a cookie store. A cookie store is needed in order to store cookies that are populated initially or that are obtained while interacting with the HTTP client. As soon as digging into this topic you will start to think about the scope/sharing of cookies.
You can enable the cookie store with one additional line of code:
DefaultHttpClient client = new DefaultHttpClient();
client.setCookieStore(new BasicCookieStore());
I know, this might be a bit late, still HTH.
I am not familiar with this library but try creating context before calling the post and reuse the same context for the get:
HttpContext context = new BasicHttpContext();
// create the client and execute the post method
HttpClient client = new DefaultHttpClient();
HttpResponse postResponse = client.execute(post,context);
...
HttpResponse getResponse = client.execute(httpget, context);

Categories

Resources