Fixes applying patch from issue #21. Workaround to solve some HTTPClient connections leak

This commit is contained in:
ccancellieri 2012-05-30 16:20:52 +02:00
parent 15341547f1
commit 314771e33d

View File

@ -36,6 +36,7 @@ import java.net.URL;
import org.apache.commons.httpclient.Credentials; import org.apache.commons.httpclient.Credentials;
import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpConnectionManager;
import org.apache.commons.httpclient.HttpStatus; import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.UsernamePasswordCredentials; import org.apache.commons.httpclient.UsernamePasswordCredentials;
import org.apache.commons.httpclient.auth.AuthScope; import org.apache.commons.httpclient.auth.AuthScope;
@ -60,67 +61,73 @@ public class HTTPUtils {
/** /**
* Performs an HTTP GET on the given URL. * Performs an HTTP GET on the given URL.
* *
* @param url The URL where to connect to. * @param url The URL where to connect to.
* @return The HTTP response as a String if the HTTP response code was 200 (OK). * @return The HTTP response as a String if the HTTP response code was 200
* (OK).
* @throws MalformedURLException * @throws MalformedURLException
*/ */
public static String get(String url) throws MalformedURLException { public static String get(String url) throws MalformedURLException {
return get(url, null, null); return get(url, null, null);
} }
/** /**
* Performs an HTTP GET on the given URL. * Performs an HTTP GET on the given URL. <BR>
* <BR>Basic auth is used if both username and pw are not null. * Basic auth is used if both username and pw are not null.
* *
* @param url The URL where to connect to. * @param url The URL where to connect to.
* @param username Basic auth credential. No basic auth if null. * @param username Basic auth credential. No basic auth if null.
* @param pw Basic auth credential. No basic auth if null. * @param pw Basic auth credential. No basic auth if null.
* @return The HTTP response as a String if the HTTP response code was 200 (OK). * @return The HTTP response as a String if the HTTP response code was 200
* (OK).
* @throws MalformedURLException * @throws MalformedURLException
*/ */
public static String get(String url, String username, String pw) throws MalformedURLException { public static String get(String url, String username, String pw) throws MalformedURLException {
GetMethod httpMethod = null; GetMethod httpMethod = null;
try { HttpClient client = new HttpClient();
HttpClient client = new HttpClient(); HttpConnectionManager connectionManager = client.getHttpConnectionManager();
try {
setAuth(client, url, username, pw); setAuth(client, url, username, pw);
httpMethod = new GetMethod(url); httpMethod = new GetMethod(url);
client.getHttpConnectionManager().getParams().setConnectionTimeout(5000); connectionManager.getParams().setConnectionTimeout(5000);
int status = client.executeMethod(httpMethod); int status = client.executeMethod(httpMethod);
if(status == HttpStatus.SC_OK) { if (status == HttpStatus.SC_OK) {
InputStream is = httpMethod.getResponseBodyAsStream(); InputStream is = httpMethod.getResponseBodyAsStream();
String response = IOUtils.toString(is); String response = IOUtils.toString(is);
if(response.trim().length()==0) { // sometime gs rest fails IOUtils.closeQuietly(is);
LOGGER.warn("ResponseBody is empty"); if (response.trim().length() == 0) { // sometime gs rest fails
return null; LOGGER.warn("ResponseBody is empty");
} else { return null;
} else {
return response; return response;
} }
} else { } else {
LOGGER.info("("+status+") " + HttpStatus.getStatusText(status) + " -- " + url ); LOGGER.info("(" + status + ") " + HttpStatus.getStatusText(status) + " -- " + url);
} }
} catch (ConnectException e) { } catch (ConnectException e) {
LOGGER.info("Couldn't connect to ["+url+"]"); LOGGER.info("Couldn't connect to [" + url + "]");
} catch (IOException e) { } catch (IOException e) {
LOGGER.info("Error talking to ["+url+"]", e); LOGGER.info("Error talking to [" + url + "]", e);
} finally { } finally {
if(httpMethod != null) if (httpMethod != null)
httpMethod.releaseConnection(); httpMethod.releaseConnection();
connectionManager.closeIdleConnections(0);
} }
return null; return null;
} }
/** /**
* PUTs a File to the given URL. * PUTs a File to the given URL. <BR>
* <BR>Basic auth is used if both username and pw are not null. * Basic auth is used if both username and pw are not null.
* *
* @param url The URL where to connect to. * @param url The URL where to connect to.
* @param file The File to be sent. * @param file The File to be sent.
* @param contentType The content-type to advert in the PUT. * @param contentType The content-type to advert in the PUT.
* @param username Basic auth credential. No basic auth if null. * @param username Basic auth credential. No basic auth if null.
* @param pw Basic auth credential. No basic auth if null. * @param pw Basic auth credential. No basic auth if null.
* @return The HTTP response as a String if the HTTP response code was 200 (OK). * @return The HTTP response as a String if the HTTP response code was 200
* (OK).
* @throws MalformedURLException * @throws MalformedURLException
* @return the HTTP response or <TT>null</TT> on errors. * @return the HTTP response or <TT>null</TT> on errors.
*/ */
@ -129,15 +136,16 @@ public class HTTPUtils {
} }
/** /**
* PUTs a String to the given URL. * PUTs a String to the given URL. <BR>
* <BR>Basic auth is used if both username and pw are not null. * Basic auth is used if both username and pw are not null.
* *
* @param url The URL where to connect to. * @param url The URL where to connect to.
* @param content The content to be sent as a String. * @param content The content to be sent as a String.
* @param contentType The content-type to advert in the PUT. * @param contentType The content-type to advert in the PUT.
* @param username Basic auth credential. No basic auth if null. * @param username Basic auth credential. No basic auth if null.
* @param pw Basic auth credential. No basic auth if null. * @param pw Basic auth credential. No basic auth if null.
* @return The HTTP response as a String if the HTTP response code was 200 (OK). * @return The HTTP response as a String if the HTTP response code was 200
* (OK).
* @throws MalformedURLException * @throws MalformedURLException
* @return the HTTP response or <TT>null</TT> on errors. * @return the HTTP response or <TT>null</TT> on errors.
*/ */
@ -151,14 +159,15 @@ public class HTTPUtils {
} }
/** /**
* PUTs a String representing an XML document to the given URL. * PUTs a String representing an XML document to the given URL. <BR>
* <BR>Basic auth is used if both username and pw are not null. * Basic auth is used if both username and pw are not null.
* *
* @param url The URL where to connect to. * @param url The URL where to connect to.
* @param content The XML content to be sent as a String. * @param content The XML content to be sent as a String.
* @param username Basic auth credential. No basic auth if null. * @param username Basic auth credential. No basic auth if null.
* @param pw Basic auth credential. No basic auth if null. * @param pw Basic auth credential. No basic auth if null.
* @return The HTTP response as a String if the HTTP response code was 200 (OK). * @return The HTTP response as a String if the HTTP response code was 200
* (OK).
* @throws MalformedURLException * @throws MalformedURLException
* @return the HTTP response or <TT>null</TT> on errors. * @return the HTTP response or <TT>null</TT> on errors.
*/ */
@ -167,14 +176,15 @@ public class HTTPUtils {
} }
/** /**
* Performs a PUT to the given URL. * Performs a PUT to the given URL. <BR>
* <BR>Basic auth is used if both username and pw are not null. * Basic auth is used if both username and pw are not null.
* *
* @param url The URL where to connect to. * @param url The URL where to connect to.
* @param requestEntity The request to be sent. * @param requestEntity The request to be sent.
* @param username Basic auth credential. No basic auth if null. * @param username Basic auth credential. No basic auth if null.
* @param pw Basic auth credential. No basic auth if null. * @param pw Basic auth credential. No basic auth if null.
* @return The HTTP response as a String if the HTTP response code was 200 (OK). * @return The HTTP response as a String if the HTTP response code was 200
* (OK).
* @throws MalformedURLException * @throws MalformedURLException
* @return the HTTP response or <TT>null</TT> on errors. * @return the HTTP response or <TT>null</TT> on errors.
*/ */
@ -183,15 +193,16 @@ public class HTTPUtils {
} }
/** /**
* POSTs a File to the given URL. * POSTs a File to the given URL. <BR>
* <BR>Basic auth is used if both username and pw are not null. * Basic auth is used if both username and pw are not null.
* *
* @param url The URL where to connect to. * @param url The URL where to connect to.
* @param file The File to be sent. * @param file The File to be sent.
* @param contentType The content-type to advert in the POST. * @param contentType The content-type to advert in the POST.
* @param username Basic auth credential. No basic auth if null. * @param username Basic auth credential. No basic auth if null.
* @param pw Basic auth credential. No basic auth if null. * @param pw Basic auth credential. No basic auth if null.
* @return The HTTP response as a String if the HTTP response code was 200 (OK). * @return The HTTP response as a String if the HTTP response code was 200
* (OK).
* @throws MalformedURLException * @throws MalformedURLException
* @return the HTTP response or <TT>null</TT> on errors. * @return the HTTP response or <TT>null</TT> on errors.
*/ */
@ -200,15 +211,16 @@ public class HTTPUtils {
} }
/** /**
* POSTs a String to the given URL. * POSTs a String to the given URL. <BR>
* <BR>Basic auth is used if both username and pw are not null. * Basic auth is used if both username and pw are not null.
* *
* @param url The URL where to connect to. * @param url The URL where to connect to.
* @param content The content to be sent as a String. * @param content The content to be sent as a String.
* @param contentType The content-type to advert in the POST. * @param contentType The content-type to advert in the POST.
* @param username Basic auth credential. No basic auth if null. * @param username Basic auth credential. No basic auth if null.
* @param pw Basic auth credential. No basic auth if null. * @param pw Basic auth credential. No basic auth if null.
* @return The HTTP response as a String if the HTTP response code was 200 (OK). * @return The HTTP response as a String if the HTTP response code was 200
* (OK).
* @throws MalformedURLException * @throws MalformedURLException
* @return the HTTP response or <TT>null</TT> on errors. * @return the HTTP response or <TT>null</TT> on errors.
*/ */
@ -222,14 +234,15 @@ public class HTTPUtils {
} }
/** /**
* POSTs a String representing an XML document to the given URL. * POSTs a String representing an XML document to the given URL. <BR>
* <BR>Basic auth is used if both username and pw are not null. * Basic auth is used if both username and pw are not null.
* *
* @param url The URL where to connect to. * @param url The URL where to connect to.
* @param content The XML content to be sent as a String. * @param content The XML content to be sent as a String.
* @param username Basic auth credential. No basic auth if null. * @param username Basic auth credential. No basic auth if null.
* @param pw Basic auth credential. No basic auth if null. * @param pw Basic auth credential. No basic auth if null.
* @return The HTTP response as a String if the HTTP response code was 200 (OK). * @return The HTTP response as a String if the HTTP response code was 200
* (OK).
* @throws MalformedURLException * @throws MalformedURLException
* @return the HTTP response or <TT>null</TT> on errors. * @return the HTTP response or <TT>null</TT> on errors.
*/ */
@ -238,14 +251,15 @@ public class HTTPUtils {
} }
/** /**
* Performs a POST to the given URL. * Performs a POST to the given URL. <BR>
* <BR>Basic auth is used if both username and pw are not null. * Basic auth is used if both username and pw are not null.
* *
* @param url The URL where to connect to. * @param url The URL where to connect to.
* @param requestEntity The request to be sent. * @param requestEntity The request to be sent.
* @param username Basic auth credential. No basic auth if null. * @param username Basic auth credential. No basic auth if null.
* @param pw Basic auth credential. No basic auth if null. * @param pw Basic auth credential. No basic auth if null.
* @return The HTTP response as a String if the HTTP response code was 200 (OK). * @return The HTTP response as a String if the HTTP response code was 200
* (OK).
* @throws MalformedURLException * @throws MalformedURLException
* @return the HTTP response or <TT>null</TT> on errors. * @return the HTTP response or <TT>null</TT> on errors.
*/ */
@ -254,129 +268,134 @@ public class HTTPUtils {
} }
/** /**
* Send an HTTP request (PUT or POST) to a server. * Send an HTTP request (PUT or POST) to a server. <BR>
* <BR>Basic auth is used if both username and pw are not null. * Basic auth is used if both username and pw are not null.
* <P> * <P>
* Only <UL> * Only
* <LI>200: OK</LI> * <UL>
* <LI>201: ACCEPTED</LI> * <LI>200: OK</LI>
* <LI>202: CREATED</LI> * <LI>201: ACCEPTED</LI>
* </UL> are accepted as successful codes; in these cases the response string will be returned. * <LI>202: CREATED</LI>
* </UL>
* are accepted as successful codes; in these cases the response string will
* be returned.
* *
* @return the HTTP response or <TT>null</TT> on errors. * @return the HTTP response or <TT>null</TT> on errors.
*/ */
private static String send(final EntityEnclosingMethod httpMethod, String url, RequestEntity requestEntity, String username, String pw) { private static String send(final EntityEnclosingMethod httpMethod, String url,
RequestEntity requestEntity, String username, String pw) {
HttpClient client = new HttpClient();
HttpConnectionManager connectionManager = client.getHttpConnectionManager();
try { try {
HttpClient client = new HttpClient();
setAuth(client, url, username, pw); setAuth(client, url, username, pw);
// httpMethod = new PutMethod(url); connectionManager.getParams().setConnectionTimeout(5000);
client.getHttpConnectionManager().getParams().setConnectionTimeout(5000); if (requestEntity != null)
if(requestEntity != null)
httpMethod.setRequestEntity(requestEntity); httpMethod.setRequestEntity(requestEntity);
int status = client.executeMethod(httpMethod); int status = client.executeMethod(httpMethod);
switch(status) { switch (status) {
case HttpURLConnection.HTTP_OK: case HttpURLConnection.HTTP_OK:
case HttpURLConnection.HTTP_CREATED: case HttpURLConnection.HTTP_CREATED:
case HttpURLConnection.HTTP_ACCEPTED: case HttpURLConnection.HTTP_ACCEPTED:
String response = IOUtils.toString(httpMethod.getResponseBodyAsStream()); String response = IOUtils.toString(httpMethod.getResponseBodyAsStream());
// LOGGER.info("================= POST " + url); // LOGGER.info("================= POST " + url);
LOGGER.info("HTTP "+ httpMethod.getStatusText()+": " + response); if (LOGGER.isInfoEnabled())
return response; LOGGER.info("HTTP " + httpMethod.getStatusText() + ": " + response);
default: return response;
LOGGER.warn("Bad response: code["+status+"]" + default:
" msg["+httpMethod.getStatusText()+"]" + LOGGER.warn("Bad response: code[" + status + "]" + " msg[" + httpMethod.getStatusText() + "]"
" url["+url+"]" + + " url[" + url + "]" + " method[" + httpMethod.getClass().getSimpleName()
" method["+httpMethod.getClass().getSimpleName()+"]: " + + "]: " + IOUtils.toString(httpMethod.getResponseBodyAsStream()));
IOUtils.toString(httpMethod.getResponseBodyAsStream()) return null;
); }
return null; } catch (ConnectException e) {
} LOGGER.info("Couldn't connect to [" + url + "]");
} catch (ConnectException e) { return null;
LOGGER.info("Couldn't connect to ["+url+"]");
return null;
} catch (IOException e) { } catch (IOException e) {
LOGGER.error("Error talking to " + url + " : " + e.getLocalizedMessage()); LOGGER.error("Error talking to " + url + " : " + e.getLocalizedMessage());
return null; return null;
} finally { } finally {
if(httpMethod != null) if (httpMethod != null)
httpMethod.releaseConnection(); httpMethod.releaseConnection();
connectionManager.closeIdleConnections(0);
} }
} }
public static boolean delete(String url, final String user, final String pw) { public static boolean delete(String url, final String user, final String pw) {
DeleteMethod httpMethod = null; DeleteMethod httpMethod = null;
HttpClient client = new HttpClient();
try { HttpConnectionManager connectionManager = client.getHttpConnectionManager();
HttpClient client = new HttpClient(); try {
setAuth(client, url, user, pw); setAuth(client, url, user, pw);
httpMethod = new DeleteMethod(url); httpMethod = new DeleteMethod(url);
client.getHttpConnectionManager().getParams().setConnectionTimeout(5000); connectionManager.getParams().setConnectionTimeout(5000);
int status = client.executeMethod(httpMethod); int status = client.executeMethod(httpMethod);
String response = ""; String response = "";
if(status == HttpStatus.SC_OK) { if (status == HttpStatus.SC_OK) {
InputStream is = httpMethod.getResponseBodyAsStream(); InputStream is = httpMethod.getResponseBodyAsStream();
response = IOUtils.toString(is); response = IOUtils.toString(is);
if(response.trim().equals("")) { // sometimes gs rest fails IOUtils.closeQuietly(is);
if(LOGGER.isDebugEnabled()) if (response.trim().equals("")) { // sometimes gs rest fails
LOGGER.debug("ResponseBody is empty (this may be not an error since we just performed a DELETE call)"); if (LOGGER.isDebugEnabled())
return true; LOGGER
} .debug("ResponseBody is empty (this may be not an error since we just performed a DELETE call)");
if(LOGGER.isDebugEnabled()) return true;
LOGGER.debug("("+status+") " + httpMethod.getStatusText() + " -- " + url ); }
return true; if (LOGGER.isDebugEnabled())
} else { LOGGER.debug("(" + status + ") " + httpMethod.getStatusText() + " -- " + url);
LOGGER.info("("+status+") " + httpMethod.getStatusText() + " -- " + url ); return true;
LOGGER.info("Response: '"+response+"'" ); } else {
} LOGGER.info("(" + status + ") " + httpMethod.getStatusText() + " -- " + url);
} catch (ConnectException e) { LOGGER.info("Response: '" + response + "'");
LOGGER.info("Couldn't connect to ["+url+"]"); }
} catch (IOException e) { } catch (ConnectException e) {
LOGGER.info("Error talking to ["+url+"]", e); LOGGER.info("Couldn't connect to [" + url + "]");
} finally { } catch (IOException e) {
if(httpMethod != null) LOGGER.info("Error talking to [" + url + "]", e);
} finally {
if (httpMethod != null)
httpMethod.releaseConnection(); httpMethod.releaseConnection();
connectionManager.closeIdleConnections(0);
} }
return false; return false;
} }
/** /**
* @return true if the server response was an HTTP_OK * @return true if the server response was an HTTP_OK
*/ */
public static boolean httpPing(String url) { public static boolean httpPing(String url) {
return httpPing(url, null, null); return httpPing(url, null, null);
} }
public static boolean httpPing(String url, String username, String pw) { public static boolean httpPing(String url, String username, String pw) {
GetMethod httpMethod = null; GetMethod httpMethod = null;
HttpClient client = new HttpClient();
try { HttpConnectionManager connectionManager = client.getHttpConnectionManager();
HttpClient client = new HttpClient(); try {
setAuth(client, url, username, pw); setAuth(client, url, username, pw);
httpMethod = new GetMethod(url); httpMethod = new GetMethod(url);
client.getHttpConnectionManager().getParams().setConnectionTimeout(2000); connectionManager.getParams().setConnectionTimeout(2000);
int status = client.executeMethod(httpMethod); int status = client.executeMethod(httpMethod);
if(status != HttpStatus.SC_OK) { if (status != HttpStatus.SC_OK) {
LOGGER.warn("PING failed at '"+url+"': ("+status+") " + httpMethod.getStatusText()); LOGGER.warn("PING failed at '" + url + "': (" + status + ") " + httpMethod.getStatusText());
return false; return false;
} else { } else {
return true; return true;
} }
} catch (ConnectException e) {
} catch (ConnectException e) { return false;
return false; } catch (IOException e) {
} catch (IOException e) { LOGGER.error(e.getLocalizedMessage(),e);
e.printStackTrace(); return false;
return false; } finally {
} finally { if (httpMethod != null)
if(httpMethod != null)
httpMethod.releaseConnection(); httpMethod.releaseConnection();
connectionManager.closeIdleConnections(0);
} }
} }
/** /**
* Used to query for REST resources. * Used to query for REST resources.
@ -387,43 +406,49 @@ public class HTTPUtils {
* @return true on 200, false on 404. * @return true on 200, false on 404.
* @throws RuntimeException on unhandled status or exceptions. * @throws RuntimeException on unhandled status or exceptions.
*/ */
public static boolean exists(String url, String username, String pw) { public static boolean exists(String url, String username, String pw) {
GetMethod httpMethod = null; GetMethod httpMethod = null;
HttpClient client = new HttpClient();
try { HttpConnectionManager connectionManager = client.getHttpConnectionManager();
HttpClient client = new HttpClient(); try {
setAuth(client, url, username, pw); setAuth(client, url, username, pw);
httpMethod = new GetMethod(url); httpMethod = new GetMethod(url);
client.getHttpConnectionManager().getParams().setConnectionTimeout(2000); connectionManager.getParams().setConnectionTimeout(2000);
int status = client.executeMethod(httpMethod); int status = client.executeMethod(httpMethod);
switch(status) { switch (status) {
case HttpStatus.SC_OK: case HttpStatus.SC_OK:
return true; return true;
case HttpStatus.SC_NOT_FOUND: case HttpStatus.SC_NOT_FOUND:
return false; return false;
default: default:
throw new RuntimeException("Unhandled response status at '"+url+"': ("+status+") " + httpMethod.getStatusText()); throw new RuntimeException("Unhandled response status at '" + url + "': (" + status + ") "
+ httpMethod.getStatusText());
} }
} catch (ConnectException e) { } catch (ConnectException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} finally { } finally {
if(httpMethod != null) if (httpMethod != null)
httpMethod.releaseConnection(); httpMethod.releaseConnection();
connectionManager.closeIdleConnections(0);
} }
} }
private static void setAuth(HttpClient client, String url, String username, String pw)
private static void setAuth(HttpClient client, String url, String username, String pw) throws MalformedURLException { throws MalformedURLException {
URL u = new URL(url); URL u = new URL(url);
if(username != null && pw != null) { if (username != null && pw != null) {
Credentials defaultcreds = new UsernamePasswordCredentials(username, pw); Credentials defaultcreds = new UsernamePasswordCredentials(username, pw);
client.getState().setCredentials(new AuthScope(u.getHost(), u.getPort()), defaultcreds); client.getState().setCredentials(new AuthScope(u.getHost(), u.getPort()), defaultcreds);
client.getParams().setAuthenticationPreemptive(true); // GS2 by default always requires authentication client.getParams().setAuthenticationPreemptive(true); // GS2 by
// default
// always
// requires
// authentication
} else { } else {
if(LOGGER.isDebugEnabled()) { if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Not setting credentials to access to " + url); LOGGER.debug("Not setting credentials to access to " + url);
} }
} }