I'm trying to connect to a Rails Application Server that requires authentication. I am using the Jakarta HTTP Client for Java on a Desktop application and it works 100%. But when the exact same code is executed on the Android Emulator I get an IOException.
Here is the code, and if anyone could help me figure out why it throws the IOException that would be greatly appreciated!
private boolean login()
{
String username, password;
DefaultHttpClient client;
AuthScope scope;
Credentials myCredentials;
CredentialsProvider provider;
HttpEntity entity;
String line;
BufferedReader reader;
InputStream instream;
//Declare & Create the HTTP Client
client = new DefaultHttpClient();
//Create our AuthScope
scope = new AuthScope("10.19.9.33", 3000);
username = "admin"
password = "pass"
//Set Credentials
myCredentials = new UsernamePasswordCredentials( username, password );
//Set Provider
provider = new BasicCredentialsProvider();
provider.setCredentials(scope, myCredentials);
//Set Credentials
client.setCredentialsProvider( provider );
String url = "http://10.19.9.33:3000/users/show/2";
HttpGet get;
//Tell where to get
get = new HttpGet( url );
HttpResponse response;
try
{
response = client.execute( get );
entity = response.getEntity();
/* Check to see if it exists */
if( entity != null )
{
instream = entity.getContent();
try {
reader = new BufferedReader(new InputStreamReader(instream));
line = reader.readLine();
if( line.equals( "HTTP Basic: Access denied.") )
return false;
while ( line != null )
{
// do something useful with the response
System.out.println(line);
line = reader.readLine();
}
return true;
}
catch (IOException ex)
{
// In case of an IOException the connection will be released
// back to the connection manager automatically
throw ex;
}
catch (RuntimeException ex)
{
// In case of an unexpected exception you may want to abort
// the HTTP request in order to shut down the underlying
// connection and release it back to the connection manager.
get.abort();
throw ex;
}
finally
{
// Closing the input stream will trigger connection release
instream.close();
}
}
}
catch( ClientProtocolException cp_ex )
{
}
catch( IOException io_ex )
{
}
return false;
}
The reason it kept triggering the IOException was because the Manifest file didn't give the Application rights to the internet
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
I'm using HttpPost for this kind of task, and never had any problem:
[...]
DefaultHttpClient client = new DefaultHttpClient();
HttpPost httppost = new HttpPost(LOGIN_SERVLET_URI);
List<BasicNameValuePair> params = new ArrayList<BasicNameValuePair>();
params.add(new BasicNameValuePair("userName", userName));
params.add(new BasicNameValuePair("password", password));
UrlEncodedFormEntity p_entity = new UrlEncodedFormEntity(params, HTTP.UTF_8);
httppost.setEntity(p_entity);
HttpResponse response = client.execute(httppost);
HttpEntity responseEntity = response.getEntity();
[...]
maybe this helps you out
Related
I am attempting to use Apache HttpClient API to access Atlassian Confluence wiki pages.
Here is my code:
public class ConcfluenceTest{
public static void main(String[] args) {
String pageID = "107544635";
String hostName = "valid_hostname";
String hostScheme = "https";
String username = "verified_username";
String password = "verified_password";
int port = 443;
//set up the username/password authentication
BasicCredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(
new AuthScope(hostName, port, AuthScope.ANY_REALM, hostScheme),
new UsernamePasswordCredentials(username, password));
HttpClient client = HttpClientBuilder.create()
.setDefaultCredentialsProvider(credsProvider)
.build();
try {
HttpGet getRequest = new HttpGet("valid_url");
System.out.println(getRequest.toString());
HttpResponse response = client.execute(getRequest);
//Parse the response
BufferedReader rd = new BufferedReader(
new InputStreamReader(response.getEntity().getContent()));
StringBuffer result = new StringBuffer();
String line = "";
while ((line = rd.readLine()) != null) {
result.append(line);
}
System.out.println(result.toString());
} catch (UnsupportedEncodingException e) {
System.out.println(e.getStackTrace());
} catch (IOException e) {
System.out.println(e.getStackTrace());
}
}
}
When I attempt to execute this code, the printed response is the HTML of the Log In screen, which means that the authentication failed. This code does, however, return the correct response when I provide it with the URL to a page that is not restricted to registered users (i.e credentials aren't required). I also tried all permutations of port/scheme.
Can someone tell me what I am missing?
Afaik, if http-basic-auth is supported, something like
user:password#server:port/path
should work, too. You could see if that works with a browser.
If Confluence dosen't support basic auth, use firebug to find out the action of the login-form (eg. the path, something like /dologin.action), the method (POST) and the Names of the user/password fields.
With that information you can create a request like this:
HttpPost httpPost = new HttpPost(fullFormActionUrlWithServerAndPort);
List <NameValuePair> nvp = new ArrayList <NameValuePair>();
nvp.add(new BasicNameValuePair("name-of-the-user-field", "your-user-name"));
nvp.add(new BasicNameValuePair("name-of-the-pass-field", "your-password"));
httpPost.setEntity(new UrlEncodedFormEntity(nvp));
I have some servlets in GAE, called from an Android app; and I want to send a POST request from one of these servlets to a php hosted in localhost using xampp. The servlet reaches an IOException when trying to read the response.
This is the code of a the sample servlet i am using:
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String result = "";
try {
URL url = new URL("http://172.25.3.50:80/tempofinito/prueba.php");
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setRequestMethod("POST");
con.setDoOutput(true);
con.setDoInput(true);
// Send
DataOutputStream wr = new DataOutputStream (
con.getOutputStream ());
wr.writeBytes ("prueba=" + URLEncoder.encode("message","UTF-8"));
wr.flush ();
wr.close ();
// Response
InputStream is = con.getInputStream();
BufferedReader rd = new BufferedReader(new InputStreamReader(is));
String line;
StringBuffer resp = new StringBuffer();
while((line = rd.readLine()) != null) {
resp.append(line);
resp.append('\r');
}
rd.close();
result = resp.toString();
} catch (MalformedURLException e) {
result = "malformed";
} catch (IOException e) {
result = "ioexception";
}
// Sends result to Android APP
PrintWriter out = response.getWriter();
out.println(result);
}
This is the php file:
<?php
$variable = $_POST["prueba"];
echo "ESTO ES UNA PRUEBA ".$variable;
?>
And this is the Android code:
new AsyncTask<Void, Void, String>() {
protected String doInBackground(Void... params) {
HttpClient client = new DefaultHttpClient();
HttpPost postMethod = new HttpPost(Globals.serverURL + "/prueba");
String result = "";
try {
// Ignore this ->
ArrayList<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(3);
nameValuePairs.add(new BasicNameValuePair("UserName", Globals.user));
nameValuePairs.add(new BasicNameValuePair("Pass", Globals.encrypt(Globals.pass)));
nameValuePairs.add(new BasicNameValuePair("Mode", "user"));
// <-
postMethod.setEntity(new UrlEncodedFormEntity(nameValuePairs));
HttpResponse response = client.execute(postMethod);
HttpEntity entity = response.getEntity();
result = EntityUtils.toString(entity);
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return result;
}
So, the APP calls the servlet "prueba". This servlet just tries to send a POST request to the php file, but reaches an IOException in the "//Response" part. I suppose I'm doing something wrong because if I copy the same code from the servlet and paste it in the Android APP, instead of the code above, it works fine.
Should I do it in a different way inside Google App Engine?
It was a stupid problem with the firewall, which was blocking the connection.
Help setting cookie to HttpClient
Created a program which logins to an external web service. However, to obtain vital information from
an HTTP GET, I am unable to pass in the cookie (generated from the login).
public class ClientHelper {
private final static String PROFILE_URL =
"http://externalservice/api/profile.json";
private final static String LOGIN_URL = "http://externalservice/api/login";
public static Cookie login(final String username, final String password) {
DefaultHttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost(LOGIN_URL);
HttpContext localContext = new BasicHttpContext();
client.getParams().setParameter("http.useragent", "Custom Browser");
client.getParams().setParameter(CoreProtocolPNames.PROTOCOL_VERSION,
HttpVersion.HTTP_1_1);
List<Cookie> cookies = null;
BasicClientCookie cookie = null;
try {
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(3);
nameValuePairs.add(new BasicNameValuePair("user", username));
nameValuePairs.add(new BasicNameValuePair("passwd", password));
UrlEncodedFormEntity entity =
new UrlEncodedFormEntity(nameValuePairs, HTTP.UTF_8);
entity.setContentType("application/x-www-form-urlencoded");
post.setEntity(new UrlEncodedFormEntity(nameValuePairs));
HttpResponse response = client.execute(post, localContext);
cookies = client.getCookieStore().getCookies();
System.out.println(cookies.get(1));
cookie = new BasicClientCookie(cookies.get(1).getName(), cookies.get(1).getValue());
cookie.setVersion(cookies.get(1).getVersion());
cookie.setDomain(cookies.get(1).getDomain());
cookie.setExpiryDate(cookies.get(1).getExpiryDate());
cookie.setPath(cookies.get(1).getPath());
BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
String line = "";
while ((line = rd.readLine()) != null) {
System.out.println(line);
}
}
catch (Throwable e) {
e.printStackTrace();
}
return cookie;
}
public static void getProfile(Cookie cookie) {
DefaultHttpClient client = new DefaultHttpClient();
HttpContext context = new BasicHttpContext();
CookieStore cookieStore = new BasicCookieStore();
cookieStore.addCookie(cookie);
client.setCookieStore(cookieStore);
context.setAttribute(ClientContext.COOKIE_STORE, cookieStore);
HttpGet get = new HttpGet(PROFILE_URL);
HttpResponse response;
try {
response = client.execute(get, context);
BufferedReader rd =
new BufferedReader(
new InputStreamReader(response.getEntity().getContent()));
String line = "";
while ((line = rd.readLine()) != null) {
System.out.println(line);
}
}
catch (ClientProtocolException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
}
}
App.java (class that uses ClientHelper):
public class App {
private static final String USER = "myusername";
private static final String PASSWD = "mypassword";
public static void main(String[] args) {
Cookie cookie = ClientHelper.login(USER, PASSWD);
ClientHelper.getProfile(cookie);
}
}
When I run App, I am able to login (I see the generated JSON) but the getProfile() method returns an empty JSON object:
{}
From the command line, using curl I am trying to emulate this:
curl -b Cookie.txt http://externalservice/api/profile.json
This actually works but not my Java program.
Try by executing this part of the code:
List<Cookie> cookies = client.getCookieStore().getCookies();
for (Cookie cookie : cookies) {
singleCookie = cookie;
}
After
HttpResponse response = client.execute(post, localContext);
After changing your code to get the cookies after the login request, you actually are getting all the cookies from the request.
I suspect the problem is that whatever Cookie it is at index 1 in the CookieStore isn't the one you need, and obviously since it's not throwing an IndexOutOfBounds exception when you do that, there's at least one other Cookie in there (at index 0). Return the list of cookies and send all of them with your profile request.
Taking your code, changing all those indexes from 1 to 0 and pointing at this simple PHP script shows that it is receiving then sending the cookies:
<?php
setcookie("TestCookie", "Some value");
print_r($_COOKIE);
?>
output:
[version: 0][name: TestCookie][value: Some+value][domain: www.mydomain.org][path: /][expiry: null]
Array
(
)
Array
(
[TestCookie] => Some value
)
I figured it out... I was creating two different HTTP clients instead of using the same one.
#Brian Roach & Raunak Agarwal thank you both very much for the help!
Here's the fix:
public static HttpClient login(final String username, final String password)
{
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost(LOGIN_URL);
client.getParams().setParameter("http.useragent", "Custom Browser");
client.getParams().setParameter(
CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);
try
{
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(3);
nameValuePairs.add(new BasicNameValuePair("user", username));
nameValuePairs.add(new BasicNameValuePair("passwd", password));
UrlEncodedFormEntity entity =
new UrlEncodedFormEntity(nameValuePairs, HTTP.UTF_8);
entity.setContentType("application/x-www-form-urlencoded");
post.setEntity(new UrlEncodedFormEntity(nameValuePairs));
HttpResponse response = client.execute(post);
BufferedReader reader =
new BufferedReader(
new InputStreamReader(response.getEntity().getContent()));
String line = "";
while ((line = reader.readLine()) != null)
{
System.out.println(line);
}
}
catch (Throwable e) { e.printStackTrace(); }
return client;
}
public static void getProfile(HttpClient client)
{
HttpGet get = new HttpGet(PROFILE_URL);
HttpResponse response;
try
{
response = client.execute(get);
BufferedReader reader =
new BufferedReader(
new InputStreamReader(response.getEntity().getContent()));
String line = "";
while ((line = reader.readLine()) != null)
{
System.out.println(line);
}
}
catch (ClientProtocolException e) { e.printStackTrace(); }
catch (IOException e) { e.printStackTrace(); }
}
I have this code, who should connect to a php remote file and should get a String representing a XML file. But something is wrong, it is giving me error 401.
The variable url is the direction of the php:
String response=getXML("http://ficticiousweb.com/scripts/getMagazinesList.php");
If i paste the real direction (that is a ficticious direction) on the webbrowser, it works and gives me the XML.
This is my code:
public String getXML(String url){
try{
StringBuilder builder = new StringBuilder();
HttpClient httpclient = new DefaultHttpClient();
HttpGet httpget = new HttpGet(url);
HttpResponse response = httpclient.execute(httpget);
int statuscode = response.getStatusLine().getStatusCode();
if(statuscode == 200)
{
HttpEntity entity = response.getEntity();
InputStream content = entity.getContent();
BufferedReader reader = new BufferedReader(new InputStreamReader(content));
String line;
while ((line = reader.readLine()) != null) builder.append(line);
}
else throw new Exception("HTTP error: " + String.valueOf(statuscode));
return builder.toString();
}catch(Exception e){e.printStackTrace();}
return null;
}
What is wrong with the code?
thanks
You need to login to the requested site in order to download or access the xml. This can be done by authenticated schema based upon what is supported. Normally, there are 2 types of schemas where used. Basic and Digest. Below code will help you for BASIC AUTH.
HttpClient httpclient = new DefaultHttpClient();
HttpResponse response;
String _username = "username";
String _password = "password";
try {
((AbstractHttpClient) httpclient).getCredentialsProvider().setCredentials(
new org.apache.http.auth.AuthScope(webhostname, webport)),
new org.apache.http.auth.UsernamePasswordCredentials(_username, _password));
response = httpclient.execute(new HttpGet(completeurlhere));
StatusLine statusLine = response.getStatusLine();
if(statusLine.getStatusCode() == HttpStatus.SC_OK) {
try {
InputStream is = response.getEntity().getContent();
this._data = is;
} catch(Exception ex) {
Log.e("DBF Error",ex.toString());
}
} else {
response.getEntity().getContent().close();
throw new IOException(statusLine.getReasonPhrase());
}
} catch(ClientProtocolException cpe) {
Log.e("ClientProtocolException # at FPT",cpe.toString());
} catch(Exception ex) {
Log.e("Exception at FETCHPROJECTASK",ex.toString());
}
Well a 401 means you aren't Authorized to do the GET request. You should ask the website how to Authenticate the request...
Authorization happens through the Authorization Header in the HTTP request. You should look into that and probably fill that header yourself with your credentials... (if the server accepts that)
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();