/** * */ package org.gcube.datatransfer.resolver.gis.geonetwork; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.StringReader; import java.io.UnsupportedEncodingException; import java.net.ConnectException; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import org.apache.commons.httpclient.Credentials; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.HttpStatus; import org.apache.commons.httpclient.UsernamePasswordCredentials; import org.apache.commons.httpclient.auth.AuthScope; import org.apache.commons.httpclient.methods.DeleteMethod; import org.apache.commons.httpclient.methods.EntityEnclosingMethod; import org.apache.commons.httpclient.methods.FileRequestEntity; import org.apache.commons.httpclient.methods.GetMethod; import org.apache.commons.httpclient.methods.InputStreamRequestEntity; import org.apache.commons.httpclient.methods.PostMethod; import org.apache.commons.httpclient.methods.PutMethod; import org.apache.commons.httpclient.methods.RequestEntity; import org.apache.commons.httpclient.methods.StringRequestEntity; import org.apache.commons.io.IOUtils; import org.apache.log4j.Logger; import org.jdom2.Document; import org.jdom2.input.SAXBuilder; /** * The Class HTTPCallsUtils. * copied by Geosolution * * @author Francesco Mangiacrapa francesco.mangiacrapa@isti.cnr.it * Apr 5, 2016 */ public class HTTPCallsUtils { private static final Logger logger = Logger.getLogger(HTTPCallsUtils.class); private final String username; private final String pw; /** * This instance is shared among the various calls, so that the * state (mainly cookies) will be preserved. */ private HttpClient client = new HttpClient(); /** * Some apps may require application/xml, so you can set it to whatever is needed. */ private String xmlContentType = "text/xml"; private int lastHttpStatus; private boolean ignoreResponseContentOnSuccess = false; /** * Instantiates a new HTTP utils. */ public HTTPCallsUtils() { this(null, null); } /** * Instantiates a new HTTP utils. * * @param userName the user name * @param password the password */ public HTTPCallsUtils(String userName, String password) { this.username = userName; this.pw = password; } /** * Sets the xml content type. * * @param xmlContentType the new xml content type */ public void setXmlContentType(String xmlContentType) { this.xmlContentType = xmlContentType; } /** * Gets the last http status. * * @return the last http status */ public int getLastHttpStatus() { return lastHttpStatus; } /** * Checks if is ignore response content on success. * * @return true, if is ignore response content on success */ public boolean isIgnoreResponseContentOnSuccess() { return ignoreResponseContentOnSuccess; } /** * Sets the ignore response content on success. * * @param ignoreResponseContentOnSuccess the new ignore response content on success */ public void setIgnoreResponseContentOnSuccess(boolean ignoreResponseContentOnSuccess) { this.ignoreResponseContentOnSuccess = ignoreResponseContentOnSuccess; } /** * Performs an HTTP GET on the given URL. * * @param url The URL where to connect to. * @return The HTTP response as a String if the HTTP response code was 200 (OK). * @throws MalformedURLException the malformed url exception */ public String get(String url) throws MalformedURLException { GetMethod httpMethod = null; try { setAuth(client, url, username, pw); httpMethod = new GetMethod(url); client.getHttpConnectionManager().getParams().setConnectionTimeout(5000); lastHttpStatus = client.executeMethod(httpMethod); if(lastHttpStatus == HttpStatus.SC_OK) { InputStream is = httpMethod.getResponseBodyAsStream(); String response = IOUtils.toString(is); if(response.trim().length()==0) { // sometime gs rest fails logger.warn("ResponseBody is empty"); return null; } else { return response; } } else { logger.info("("+lastHttpStatus+") " + HttpStatus.getStatusText(lastHttpStatus) + " -- " + url ); } } catch (ConnectException e) { logger.info("Couldn't connect to ["+url+"]"); } catch (IOException e) { logger.info("Error talking to ["+url+"]", e); } finally { if(httpMethod != null) httpMethod.releaseConnection(); } return null; } /** * Performs an HTTP GET on the given URL and return reponse body. * * @param url The URL where to connect to. * @return The HTTP response as a String if the HTTP response code was 200 (OK). * @throws MalformedURLException the malformed url exception */ public InputStream getBody(String url) throws MalformedURLException { GetMethod httpMethod = null; try { setAuth(client, url, username, pw); httpMethod = new GetMethod(url); client.getHttpConnectionManager().getParams().setConnectionTimeout(5000); lastHttpStatus = client.executeMethod(httpMethod); if(lastHttpStatus == HttpStatus.SC_OK) { return httpMethod.getResponseBodyAsStream(); } else { logger.info("("+lastHttpStatus+") " + HttpStatus.getStatusText(lastHttpStatus) + " -- " + url ); } } catch (ConnectException e) { logger.info("Couldn't connect to ["+url+"]"); } catch (IOException e) { logger.info("Error talking to ["+url+"]", e); } finally { if(httpMethod != null) httpMethod.releaseConnection(); } return null; } //========================================================================== //=== PUT //========================================================================== /** * Gets the client. * * @return the client */ public HttpClient getClient() { return client; } /** * PUTs a String representing an XML document to the given URL. * * @param url The URL where to connect to. * @param content The XML content to be sent as a String. * @return The HTTP response as a String if the HTTP response code was 200 (OK). * the HTTP response or null on errors. */ public String putXml(String url, String content) { return put(url, content, xmlContentType); } /** * PUTs a File to the given URL. * * @param url The URL where to connect to. * @param file The File to be sent. * @param contentType The content-type to advert in the PUT. * @return The HTTP response as a String if the HTTP response code was 200 (OK). * the HTTP response or null on errors. */ public String put(String url, File file, String contentType) { return put(url, new FileRequestEntity(file, contentType)); } /** * PUTs a String to the given URL. * * @param url The URL where to connect to. * @param content The content to be sent as a String. * @param contentType The content-type to advert in the PUT. * @return The HTTP response as a String if the HTTP response code was 200 (OK). * the HTTP response or null on errors. */ public String put(String url, String content, String contentType) { try { return put(url, new StringRequestEntity(content, contentType, null)); } catch (UnsupportedEncodingException ex) { logger.error("Cannot PUT " + url, ex); return null; } } /** * Performs a PUT to the given URL. * * @param url The URL where to connect to. * @param requestEntity The request to be sent. * @return The HTTP response as a String if the HTTP response code was 200 (OK). * the HTTP response or null on errors. */ public String put(String url, RequestEntity requestEntity) { return send(new PutMethod(url), url, requestEntity); } //========================================================================== //=== POST //========================================================================== /** * POSTs a String representing an XML document to the given URL. * * @param url The URL where to connect to. * @param content The XML content to be sent as a String. * @return The HTTP response as a String if the HTTP response code was 200 (OK). * the HTTP response or null on errors. */ public String postXml(String url, String content) { return post(url, content, xmlContentType); } /** * POSTs a Stream content representing an XML document to the given URL. * * @param url The URL where to connect to. * @param content The content to be sent as an InputStream. * @return The HTTP response as a String if the HTTP response code was 200 (OK). * the HTTP response or null on errors. */ public String postXml(String url, InputStream content) { return post(url, content, xmlContentType); } /** * POSTs a File to the given URL. * * @param url The URL where to connect to. * @param file The File to be sent. * @param contentType The content-type to advert in the POST. * @return The HTTP response as a String if the HTTP response code was 200 (OK). * the HTTP response or null on errors. */ public String post(String url, File file, String contentType) { return post(url, new FileRequestEntity(file, contentType)); } /** * POSTs a String to the given URL. * * @param url The URL where to connect to. * @param content The content to be sent as a String. * @param contentType The content-type to advert in the POST. * @return The HTTP response as a String if the HTTP response code was 200 (OK). * the HTTP response or null on errors. */ public String post(String url, String content, String contentType) { try { return post(url, new StringRequestEntity(content, contentType, null)); } catch (UnsupportedEncodingException ex) { logger.error("Cannot POST " + url, ex); return null; } } /** * POSTs a Stream content to the given URL. * * @param url The URL where to connect to. * @param content The content to be sent as an InputStream. * @param contentType The content-type to advert in the POST. * @return The HTTP response as a String if the HTTP response code was 200 (OK). * the HTTP response or null on errors. */ public String post(String url, InputStream content, String contentType) { return post(url, new InputStreamRequestEntity(content, contentType)); } /** * Performs a POST to the given URL. *
Basic auth is used if both username and pw are not null. * * @param url The URL where to connect to. * @param requestEntity The request to be sent. * @return The HTTP response as a String if the HTTP response code was 200 (OK). * the HTTP response or null on errors. */ public String post(String url, RequestEntity requestEntity) { return send(new PostMethod(url), url, requestEntity); } //========================================================================== //=== HTTP requests //========================================================================== /** * Send an HTTP request (PUT or POST) to a server. *
Basic auth is used if both username and pw are not null. *

* Only

are accepted as successful codes; in these cases the response string will be returned. * * @param httpMethod the http method * @param url the url * @param requestEntity the request entity * @return the HTTP response or null on errors. */ protected String send(final EntityEnclosingMethod httpMethod, String url, RequestEntity requestEntity) { try { setAuth(client, url, username, pw); client.getHttpConnectionManager().getParams().setConnectionTimeout(5000); if(requestEntity != null) httpMethod.setRequestEntity(requestEntity); lastHttpStatus = client.executeMethod(httpMethod); switch(lastHttpStatus) { case HttpURLConnection.HTTP_OK: case HttpURLConnection.HTTP_CREATED: case HttpURLConnection.HTTP_ACCEPTED: if(logger.isDebugEnabled()) logger.debug("HTTP "+ httpMethod.getStatusText() + " <-- " + url); if(ignoreResponseContentOnSuccess) return ""; String response = IOUtils.toString(httpMethod.getResponseBodyAsStream()); return response; default: String badresponse = IOUtils.toString(httpMethod.getResponseBodyAsStream()); String message = getGeoNetworkErrorMessage(badresponse); logger.warn("Bad response: "+lastHttpStatus + " " + httpMethod.getStatusText() + " -- " + httpMethod.getName() + " " +url + " : " + message ); if(logger.isDebugEnabled()) logger.debug("GeoNetwork response:\n"+badresponse); return null; } } catch (ConnectException e) { logger.info("Couldn't connect to ["+url+"]"); return null; } catch (IOException e) { logger.error("Error talking to " + url + " : " + e.getLocalizedMessage()); return null; } finally { if(httpMethod != null) httpMethod.releaseConnection(); } } /** * Send an HTTP request (PUT or POST) to a server. *
Basic auth is used if both username and pw are not null. *

* Only

are accepted as successful codes; in these cases the response string will be returned. * * @param httpMethod the http method * @param url the url * @param requestEntity the request entity * @return the HTTP response or null on errors. */ protected InputStream sendPost(final EntityEnclosingMethod httpMethod, String url, RequestEntity requestEntity) { try { setAuth(client, url, username, pw); client.getHttpConnectionManager().getParams().setConnectionTimeout(5000); if(requestEntity != null) httpMethod.setRequestEntity(requestEntity); lastHttpStatus = client.executeMethod(httpMethod); switch(lastHttpStatus) { case HttpURLConnection.HTTP_OK: case HttpURLConnection.HTTP_CREATED: case HttpURLConnection.HTTP_ACCEPTED: if(logger.isDebugEnabled()) logger.debug("HTTP "+ httpMethod.getStatusText() + " <-- " + url); return httpMethod.getResponseBodyAsStream(); default: logger.warn("Bad response: "+lastHttpStatus + " " + httpMethod.getStatusText() + " -- " + httpMethod.getName() + " " +url ); return httpMethod.getResponseBodyAsStream(); } } catch (ConnectException e) { logger.info("Couldn't connect to ["+url+"]"); return null; } catch (IOException e) { logger.error("Error talking to " + url + " : " + e.getLocalizedMessage()); return null; } finally { if(httpMethod != null) httpMethod.releaseConnection(); } } /** * Delete. * * @param url the url * @return true, if successful */ public boolean delete(String url) { DeleteMethod httpMethod = null; try { // HttpClient client = new HttpClient(); setAuth(client, url, username, pw); httpMethod = new DeleteMethod(url); client.getHttpConnectionManager().getParams().setConnectionTimeout(5000); lastHttpStatus = client.executeMethod(httpMethod); String response = ""; if(lastHttpStatus == HttpStatus.SC_OK) { if(logger.isDebugEnabled()) logger.debug("("+lastHttpStatus+") " + httpMethod.getStatusText() + " -- " + url ); if( ! ignoreResponseContentOnSuccess) { InputStream is = httpMethod.getResponseBodyAsStream(); response = IOUtils.toString(is); if(response.trim().equals("")) { if(logger.isDebugEnabled()) logger.debug("ResponseBody is empty (this may be not an error since we just performed a DELETE call)"); } } return true; } else { logger.info("("+lastHttpStatus+") " + httpMethod.getStatusText() + " -- " + url ); logger.info("Response: '"+response+"'" ); } } catch (ConnectException e) { logger.info("Couldn't connect to ["+url+"]"); } catch (IOException e) { logger.info("Error talking to ["+url+"]", e); } finally { if(httpMethod != null) httpMethod.releaseConnection(); } return false; } /** * Http ping. * * @param url the url * @return true if the server response was an HTTP_OK */ public boolean httpPing(String url) { GetMethod httpMethod = null; try { // HttpClient client = new HttpClient(); setAuth(client, url, username, pw); httpMethod = new GetMethod(url); client.getHttpConnectionManager().getParams().setConnectionTimeout(2000); lastHttpStatus = client.executeMethod(httpMethod); if(lastHttpStatus != HttpStatus.SC_OK) { logger.warn("PING failed at '"+url+"': ("+lastHttpStatus+") " + httpMethod.getStatusText()); return false; } else { return true; } } catch (ConnectException e) { return false; } catch (IOException e) { e.printStackTrace(); return false; } finally { if(httpMethod != null) httpMethod.releaseConnection(); } } /** * Used to query for REST resources. * * @param url The URL of the REST resource to query about. * @return true on 200, false on 404. */ public boolean exists(String url) { GetMethod httpMethod = null; try { // HttpClient client = new HttpClient(); setAuth(client, url, username, pw); httpMethod = new GetMethod(url); client.getHttpConnectionManager().getParams().setConnectionTimeout(2000); lastHttpStatus = client.executeMethod(httpMethod); switch(lastHttpStatus) { case HttpStatus.SC_OK: return true; case HttpStatus.SC_NOT_FOUND: return false; default: throw new RuntimeException("Unhandled response status at '"+url+"': ("+lastHttpStatus+") " + httpMethod.getStatusText()); } } catch (ConnectException e) { throw new RuntimeException(e); } catch (IOException e) { throw new RuntimeException(e); } finally { if(httpMethod != null) httpMethod.releaseConnection(); } } /** * Sets the auth. * * @param client the client * @param url the url * @param username the username * @param pw the pw * @throws MalformedURLException the malformed url exception */ private static void setAuth(HttpClient client, String url, String username, String pw) throws MalformedURLException { URL u = new URL(url); if(username != null && pw != null) { Credentials defaultcreds = new UsernamePasswordCredentials(username, pw); client.getState().setCredentials(new AuthScope(u.getHost(), u.getPort()), defaultcreds); client.getParams().setAuthenticationPreemptive(true); // GS2 by default always requires authentication } else { if(logger.isTraceEnabled()) { logger.trace("Not setting credentials to access to " + url); } } } /** * Gets the geo network error message. * * @param msg the msg * @return the geo network error message */ protected static String getGeoNetworkErrorMessage(String msg) { try { SAXBuilder builder = new SAXBuilder(); Document error = builder.build(new StringReader(msg)); return error.getRootElement().getChildText("message"); } catch (Exception ex) { return "-"; } } /** * Gets the geo network error message. * * @param msg the msg * @return the geo network error message */ protected static String getGeoNetworkErrorMessage(InputStream msg) { try { SAXBuilder builder = new SAXBuilder(); Document error = builder.build(msg); return error.getRootElement().getChildText("message"); } catch (Exception ex) { return "-"; } } }