Java tutorial
/** * @file HttpTransport.java * @brief HTTP Transport Support * @author Doug Anson * @version 1.0 * @see * * Copyright 2015. ARM Ltd. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package com.arm.connector.bridge.transport; import com.arm.connector.bridge.core.BaseClass; import com.arm.connector.bridge.core.ErrorLogger; import com.arm.connector.bridge.preferences.PreferenceManager; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.security.cert.X509Certificate; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSession; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import org.apache.commons.codec.binary.Base64; /** * HTTP Transport Support * * @author Doug Anson */ public class HttpTransport extends BaseClass { private int m_last_response_code = 0; private String m_auth_qualifier_default = "bearer"; private String m_auth_qualifier = this.m_auth_qualifier_default; private String m_basic_auth_qualifier = "Basic"; private String m_etag_value = null; private String m_if_match_header_value = null; // constructor /** * * @param error_logger * @param preference_manager */ public HttpTransport(ErrorLogger error_logger, PreferenceManager preference_manager) { super(error_logger, preference_manager); String auth_qualifier = this.prefValue("http_auth_qualifier"); if (auth_qualifier != null && auth_qualifier.length() > 0) { this.m_auth_qualifier_default = auth_qualifier; this.m_auth_qualifier = this.m_auth_qualifier_default; } this.errorLogger().info("HTTP: Authorization Qualifier set to: " + this.m_auth_qualifier); } // set the authorization qualifier public void setAuthorizationQualifier(String qualifier) { if (qualifier != null && qualifier.length() > 0) { this.m_auth_qualifier = qualifier; } } // reset the authorization qualifier private void resetAuthorizationQualifier() { this.m_auth_qualifier = this.m_auth_qualifier_default; } // set the ETag value public void setETagValue(String etag) { this.m_etag_value = etag; } // reset the ETag value private void resetETagValue() { this.m_etag_value = null; } // set the If-Match value public void setIfMatchValue(String ifMatch) { this.m_if_match_header_value = ifMatch; } // reset the If-Match value private void resetIfMatchValue() { this.m_if_match_header_value = null; } // execute GET over http /** * * @param url_str * @param username * @param password * @param data * @param content_type * @param auth_domain * @return */ public String httpGet(String url_str, String username, String password, String data, String content_type, String auth_domain) { return this.doHTTP("GET", url_str, username, password, data, content_type, auth_domain, true, false, false, false, null); } /** * * @param url_str * @param api_token * @param data * @param content_type * @param auth_domain * @return */ public String httpGetApiTokenAuth(String url_str, String api_token, String data, String content_type, String auth_domain) { return this.doHTTP("GET", url_str, null, null, data, content_type, auth_domain, true, false, false, true, api_token); } // execute GET over https /** * * @param url_str * @param username * @param password * @param data * @param content_type * @param auth_domain * @return */ public String httpsGet(String url_str, String username, String password, String data, String content_type, String auth_domain) { return this.doHTTP("GET", url_str, username, password, data, content_type, auth_domain, true, false, true, false, null); } /** * * @param url_str * @param api_token * @param data * @param content_type * @param auth_domain * @return */ public String httpsGetApiTokenAuth(String url_str, String api_token, String data, String content_type, String auth_domain) { return this.doHTTP("GET", url_str, null, null, data, content_type, auth_domain, true, false, true, true, api_token); } // execute POST over https /** * * @param url_str * @param username * @param password * @param data * @param content_type * @param auth_domain * @return */ public String httpPost(String url_str, String username, String password, String data, String content_type, String auth_domain) { return this.doHTTP("POST", url_str, username, password, data, content_type, auth_domain, true, true, false, false, null); } /** * * @param url_str * @param api_token * @param data * @param content_type * @param auth_domain * @return */ public String httpPostApiTokenAuth(String url_str, String api_token, String data, String content_type, String auth_domain) { return this.doHTTP("POST", url_str, null, null, data, content_type, auth_domain, true, true, false, true, api_token); } // execute POST over https /** * * @param url_str * @param username * @param password * @param data * @param content_type * @param auth_domain * @return */ public String httpsPost(String url_str, String username, String password, String data, String content_type, String auth_domain) { return this.doHTTP("POST", url_str, username, password, data, content_type, auth_domain, true, true, true, false, null); } /** * * @param url_str * @param api_token * @param data * @param content_type * @param auth_domain * @return */ public String httpsPostApiTokenAuth(String url_str, String api_token, String data, String content_type, String auth_domain) { return this.doHTTP("POST", url_str, null, null, data, content_type, auth_domain, true, true, true, true, api_token); } // execute PUT over http /** * * @param url_str * @param username * @param password * @param data * @param content_type * @param auth_domain * @return */ public String httpPut(String url_str, String username, String password, String data, String content_type, String auth_domain) { return this.doHTTP("PUT", url_str, username, password, data, content_type, auth_domain, true, true, false, false, null); } /** * * @param url_str * @param api_token * @param data * @param content_type * @param auth_domain * @return */ public String httpPutApiTokenAuth(String url_str, String api_token, String data, String content_type, String auth_domain) { return this.doHTTP("PUT", url_str, null, null, data, content_type, auth_domain, true, true, false, true, api_token); } // execute PUT over https /** * * @param url_str * @param username * @param password * @param data * @param content_type * @param auth_domain * @return */ public String httpsPut(String url_str, String username, String password, String data, String content_type, String auth_domain) { return this.doHTTP("PUT", url_str, username, password, data, content_type, auth_domain, true, true, true, false, null); } /** * * @param url_str * @param api_token * @param data * @param content_type * @param auth_domain * @return */ public String httpsPutApiTokenAuth(String url_str, String api_token, String data, String content_type, String auth_domain) { return this.doHTTP("PUT", url_str, null, null, data, content_type, auth_domain, true, true, true, true, api_token); } // execute PUT over http /** * * @param url_str * @param username * @param password * @param data * @param content_type * @param auth_domain * @param expect_response * @return */ public String httpPut(String url_str, String username, String password, String data, String content_type, String auth_domain, boolean expect_response) { return this.doHTTP("PUT", url_str, username, password, data, content_type, auth_domain, expect_response, true, false, false, null); } /** * * @param url_str * @param api_token * @param data * @param content_type * @param auth_domain * @param expect_response * @return */ public String httpPutApiTokenAuth(String url_str, String api_token, String data, String content_type, String auth_domain, boolean expect_response) { return this.doHTTP("PUT", url_str, null, null, data, content_type, auth_domain, expect_response, true, false, true, api_token); } // execute PUT over https /** * * @param url_str * @param username * @param password * @param data * @param content_type * @param auth_domain * @param expect_response * @return */ public String httpsPut(String url_str, String username, String password, String data, String content_type, String auth_domain, boolean expect_response) { return this.doHTTP("PUT", url_str, username, password, data, content_type, auth_domain, expect_response, true, true, false, null); } /** * * @param url_str * @param api_token * @param data * @param content_type * @param auth_domain * @param expect_response * @return */ public String httpsPutApiTokenAuth(String url_str, String api_token, String data, String content_type, String auth_domain, boolean expect_response) { return this.doHTTP("PUT", url_str, null, null, data, content_type, auth_domain, expect_response, true, true, true, api_token); } // execute DELETE over http /** * * @param url_str * @param username * @param password * @param data * @param content_type * @param auth_domain * @return */ public String httpDelete(String url_str, String username, String password, String data, String content_type, String auth_domain) { return this.doHTTP("DELETE", url_str, username, password, data, content_type, auth_domain, true, true, false, false, null); } /** * * @param url_str * @param api_token * @param data * @param content_type * @param auth_domain * @return */ public String httpDeleteApiTokenAuth(String url_str, String api_token, String data, String content_type, String auth_domain) { return this.doHTTP("DELETE", url_str, null, null, data, content_type, auth_domain, true, true, false, true, api_token); } // execute DELETE over https /** * * @param url_str * @param username * @param password * @param data * @param content_type * @param auth_domain * @return */ public String httpsDelete(String url_str, String username, String password, String data, String content_type, String auth_domain) { return this.doHTTP("DELETE", url_str, username, password, data, content_type, auth_domain, true, true, true, false, null); } /** * * @param url_str * @param api_token * @param data * @param content_type * @param auth_domain * @return */ public String httpsDeleteApiTokenAuth(String url_str, String api_token, String data, String content_type, String auth_domain) { return this.doHTTP("DELETE", url_str, null, null, data, content_type, auth_domain, true, true, true, true, api_token); } // get the requested path component of a given URL /** * * @param url * @param index * @param whole_path * @return */ public String getPathComponent(String url, int index, boolean whole_path) { try { return this.getPathComponent(new URL(url), index, whole_path); } catch (MalformedURLException ex) { this.errorLogger().critical("Caught Exception parsing URL: " + url + " in getPathComponent: ", ex); } return null; } private String getPathComponent(URL url, int index, boolean whole_path) { String value = null; if (whole_path) { value = url.getPath().trim(); } else { String path = url.getPath().replace("/", " ").trim(); String list[] = path.split(" "); if (index >= 0 && index < list.length) { value = list[index]; } if (index < 0) { return list[list.length - 1]; } } return value; } private void saveResponseCode(int response_code) { this.m_last_response_code = response_code; } public int getLastResponseCode() { return this.m_last_response_code; } // perform an authenticated HTML operation @SuppressWarnings("empty-statement") private String doHTTP(String verb, String url_str, String username, String password, String data, String content_type, String auth_domain, boolean doInput, boolean doOutput, boolean doSSL, boolean use_api_token, String api_token) { String result = ""; String line = ""; URLConnection connection = null; SSLContext sc = null; try { URL url = new URL(url_str); // Http Connection and verb if (doSSL) { // Create a trust manager that does not validate certificate chains TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() { @Override public X509Certificate[] getAcceptedIssuers() { return null; } @Override public void checkClientTrusted(X509Certificate[] certs, String authType) { } @Override public void checkServerTrusted(X509Certificate[] certs, String authType) { } } }; // Install the all-trusting trust manager try { sc = SSLContext.getInstance("TLS"); sc.init(null, trustAllCerts, new SecureRandom()); HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() { @Override public boolean verify(String hostname, SSLSession session) { return true; } }); } catch (NoSuchAlgorithmException | KeyManagementException e) { // do nothing ; } // open the SSL connction connection = (HttpsURLConnection) (url.openConnection()); ((HttpsURLConnection) connection).setRequestMethod(verb); ((HttpsURLConnection) connection).setSSLSocketFactory(sc.getSocketFactory()); ((HttpsURLConnection) connection).setHostnameVerifier(new HostnameVerifier() { @Override public boolean verify(String hostname, SSLSession session) { return true; } }); } else { connection = (HttpURLConnection) (url.openConnection()); ((HttpURLConnection) connection).setRequestMethod(verb); } connection.setDoInput(doInput); if (doOutput && data != null && data.length() > 0) { connection.setDoOutput(doOutput); } else { connection.setDoOutput(false); } // enable basic auth if requested if (use_api_token == false && username != null && username.length() > 0 && password != null && password.length() > 0) { String encoding = Base64.encodeBase64String((username + ":" + password).getBytes()); connection.setRequestProperty("Authorization", this.m_basic_auth_qualifier + " " + encoding); //this.errorLogger().info("Basic Authorization: " + username + ":" + password + ": " + encoding); } // enable ApiTokenAuth auth if requested if (use_api_token == true && api_token != null && api_token.length() > 0) { // use qualification for the authorization header... connection.setRequestProperty("Authorization", this.m_auth_qualifier + " " + api_token); //this.errorLogger().info("ApiTokenAuth Authorization: " + api_token); // Always reset to the established default this.resetAuthorizationQualifier(); } // ETag support if requested if (this.m_etag_value != null && this.m_etag_value.length() > 0) { // set the ETag header value connection.setRequestProperty("ETag", this.m_etag_value); //this.errorLogger().info("ETag Value: " + this.m_etag_value); // Always reset to the established default this.resetETagValue(); } // If-Match support if requested if (this.m_if_match_header_value != null && this.m_if_match_header_value.length() > 0) { // set the If-Match header value connection.setRequestProperty("If-Match", this.m_if_match_header_value); //this.errorLogger().info("If-Match Value: " + this.m_if_match_header_value); // Always reset to the established default this.resetIfMatchValue(); } // specify content type if requested if (content_type != null && content_type.length() > 0) { connection.setRequestProperty("Content-Type", content_type); connection.setRequestProperty("Accept", "*/*"); } // add Connection: keep-alive (does not work...) //connection.setRequestProperty("Connection", "keep-alive"); // special gorp for HTTP DELETE if (verb != null && verb.equalsIgnoreCase("delete")) { connection.setRequestProperty("Access-Control-Allow-Methods", "OPTIONS, DELETE"); } // specify domain if requested if (auth_domain != null && auth_domain.length() > 0) { connection.setRequestProperty("Domain", auth_domain); } // DEBUG dump the headers //if (doSSL) // this.errorLogger().info("HTTP: Headers: " + ((HttpsURLConnection)connection).getRequestProperties()); //else // this.errorLogger().info("HTTP: Headers: " + ((HttpURLConnection)connection).getRequestProperties()); // specify data if requested - assumes it properly escaped if necessary if (doOutput && data != null && data.length() > 0) { try (OutputStreamWriter out = new OutputStreamWriter(connection.getOutputStream())) { out.write(data); } } // setup the output if requested if (doInput) { try { try (InputStream content = (InputStream) connection.getInputStream(); BufferedReader in = new BufferedReader(new InputStreamReader(content))) { while ((line = in.readLine()) != null) { result += line; } } } catch (java.io.FileNotFoundException ex) { this.errorLogger().info("HTTP(" + verb + ") empty response (OK)."); result = ""; } } else { // no result expected result = ""; } // save off the HTTP response code... if (doSSL) this.saveResponseCode(((HttpsURLConnection) connection).getResponseCode()); else this.saveResponseCode(((HttpURLConnection) connection).getResponseCode()); // DEBUG //if (doSSL) // this.errorLogger().info("HTTP(" + verb +") URL: " + url_str + " Data: " + data + " Response code: " + ((HttpsURLConnection)connection).getResponseCode()); //else // this.errorLogger().info("HTTP(" + verb +") URL: " + url_str + " Data: " + data + " Response code: " + ((HttpURLConnection)connection).getResponseCode()); } catch (IOException ex) { this.errorLogger().warning("Caught Exception in doHTTP(" + verb + "): " + ex.getMessage()); result = null; } // return the result return result; } }