All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.qas.api.http.basic.HttpUrlConnectionFactory Maven / Gradle / Ivy

The newest version!
package org.qas.api.http.basic;

import org.qas.api.ClientConfiguration;
import org.qas.api.Request;
import org.qas.api.http.ExecutionContext;
import org.qas.api.internal.util.Encoders;
import org.qas.api.internal.util.Https;
import org.qas.api.internal.util.google.base.Charsets;
import org.qas.api.internal.util.google.base.Strings;
import org.qas.api.internal.util.google.net.HttpHeaders;

import javax.net.ssl.*;
import java.io.IOException;
import java.net.*;
import java.nio.charset.Charset;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Iterator;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * HttpUrlConnectionFactory
 *
 * @author Dzung Nguyen
 * @version $Id HttpUrlConnectionFactory 2014-03-27 11:48:30z dungvnguyen $
 * @since 1.0
 */
class HttpUrlConnectionFactory {
  //~ class properties ========================================================
  private static final Logger LOG = Logger.getLogger(HttpUrlConnectionFactory.class.getName());
  private static final Charset DEFAULT_ENCODING = Charsets.UTF_8;

  // initialize default resource.
  static {
    try {
      TrustManager[] trustAllCerts = { new TrustingX509TrustManager() };

      // set the context.
      SSLContext context = SSLContext.getInstance("SSL");
      context.init(null, trustAllCerts, new SecureRandom());

      HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory());
      HttpsURLConnection.setDefaultHostnameVerifier(new TrustHostnameVerifier());
    } catch (Exception ex) {
      LOG.log(Level.WARNING, "Could not initialize the SSL context.", ex);
    }
  }

  //~ class members ===========================================================
  /**
   * Creates un {@link HttpURLConnection} based on the specified request and
   * populates any parameters, headers, from the original request.
   *
   * @param request the request to converter to {@link HttpURLConnection}
   *                object.
   * @param redirectUri the URI to send the request to.
   * @param configuration The configuration to reading configure from environment.
   * @param context The execution context of the HTTP method to be execute.
   * @return The converted {@link HttpURLConnection} object with any parameters,
   *         headers from the original request.
   */
  static HttpURLConnection createHttpRequest(Request request,
                                             URI redirectUri,
                                             ClientConfiguration configuration,
                                             ExecutionContext context) {
    // processing the request endpoint.
    URI endpoint = (redirectUri == null ? request.getEndpoint() : redirectUri);
    String uri = endpoint.toString();

    if (!Strings.isNullOrEmpty(request.getResourcePath())) {
      if (request.getResourcePath().startsWith("/")) {
        if (uri.endsWith("/")) {
          uri = uri.substring(0, uri.length() - 1);
        }
      } else if (!uri.endsWith("/")) {
        uri += "/";
      }

      uri += request.getResourcePath();
    } else if (!uri.endsWith("/")) {
      uri += "/";
    }

    // process the request parameter.
    String queryParams = Https.toQueryString(request.getParameters(), Charsets.UTF_8);

    // create the request.
    if (!Strings.isNullOrEmpty(queryParams)
        && !Https.usePayloadForQueryParameters(request)) {
      uri += "?" + queryParams;
    }

    // open the connection.
    HttpURLConnection connection = createConnection(request, uri, configuration);

    // setting connection configuration.
    connection.setConnectTimeout(configuration.getConnectionTimeout());
    connection.setReadTimeout(configuration.getSocketTimeout());

    try {
      connection.setRequestMethod(request.getHttpMethod().name());
    } catch (ProtocolException pex) {
      LOG.log(Level.SEVERE, "An error occurs when setting request method: " + request.getHeaders() + "\n", pex);
    }

    switch (request.getHttpMethod()) {
      case POST:
        if (request.getContent() != null || !Strings.isNullOrEmpty(queryParams)) {
          connection.setDoOutput(true);
        }
        break;
      case PUT:
        if (request.getContent() != null || !Strings.isNullOrEmpty(queryParams)) {
          connection.setDoOutput(true);
        }
        break;
      case GET:
      case DELETE:
      case HEAD:
      default:
        break;
    }

    // setting the headers.
    prepareHeader(connection, request, redirectUri, configuration, context);

    // return the connection.
    return connection;
  }

  private static void prepareHeader(HttpURLConnection connection,
                                    Request request,
                                    URI redirectUri,
                                    ClientConfiguration configuration,
                                    ExecutionContext context) {
    // setting host.
    URI endpoint = (redirectUri == null ? request.getEndpoint() : redirectUri);
    String host = endpoint.getHost();
    if (Https.isUsingNonDefaultPort(endpoint)) {
      host += ":" + endpoint.getPort();
    }
    connection.setRequestProperty(HttpHeaders.HOST, host);

    // setting request header.
    Map headers = request.getHeaders();
    String header;
    for (Iterator headerIt = headers.keySet().iterator();
         headerIt.hasNext(); ) {
      header = headerIt.next();

      if ("content-length".equals(header.toLowerCase())
          || "host".equals(header.toLowerCase())) continue;
      connection.setRequestProperty(header, headers.get(header));
    }

    // set content type.
    String contentType = headers.get("Content-Type");
    if (contentType == null || "".equals(contentType)) {
      connection.setRequestProperty("Content-Type",
          "application/x-www-form-urlencoded; charset="
              + DEFAULT_ENCODING.name().toLowerCase());
    }

    // set the user agent.
    if (context != null && context.getContextUserAgent() != null) {
      connection.setRequestProperty("User-Agent",
          createUserAgentString(configuration, context.getContextUserAgent()));
    }
  }

  private static String createUserAgentString(ClientConfiguration configuration,
                                              String contextUserAgent) {
    if (configuration.getUserAgent().contains(contextUserAgent)) {
      return configuration.getUserAgent();
    } else {
      return configuration.getUserAgent() + " " + contextUserAgent;
    }
  }

  /**
   * Creates the {@link HttpURLConnection URL connection} from the uri and the
   * configuration.
   *
   * @param request the specified request to connect to.
   * @param uri the URI to make the connection to.
   * @param configuration the client configuration used to create the
   *                      connection.
   * @return the {@link HttpURLConnection} object.
   */
  private static HttpURLConnection createConnection(Request request, String uri,
                                                    ClientConfiguration configuration) {
    String proxyHost = configuration.getProxyHost();
    int proxyPort = configuration.getProxyPort();

    // make connection.
    HttpURLConnection connection;
    try {
      final URL url = new URL(uri);

      if (!Strings.isNullOrEmpty(proxyHost) && proxyPort > 0) { // setting up the proxy.
        Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyHost, proxyPort));

        // open the connection.
        connection = (HttpURLConnection) url.openConnection(proxy);

        // setting up the proxy username and password.
        final String username = configuration.getProxyUsername();
        final String password = configuration.getProxyPassword();
        final String domain = configuration.getProxyDomain();

        if (!Strings.isNullOrEmpty(username) && !Strings.isNullOrEmpty(password)) {
          Authenticator.setDefault(new Authenticator() {
            @Override
            protected PasswordAuthentication getPasswordAuthentication() {
              return new PasswordAuthentication(
                  Strings.isNullOrEmpty(domain) ? username : domain + "\\\\" + username,
                  password.toCharArray()
              );
            }
          });

          // setting proxy password.
          String upEncoder = Strings.isNullOrEmpty(domain) ? username + ':' + password
              : domain + "\\\\" + username + ':' + password;
          upEncoder = new String(Encoders.base64Encode(upEncoder.getBytes()));
          connection.setRequestProperty("Proxy-Authorization", "Basic " + upEncoder);
        }
      } else {
        connection = (HttpURLConnection) url.openConnection();
      }
    } catch (MalformedURLException muex) {
      throw new AssertionError(muex);
    } catch (IOException ioex) {
      throw new AssertionError(ioex);
    }

    // setting up the user agent.
    String userAgent = configuration.getUserAgent();
    if (!(userAgent.equals(ClientConfiguration.DEFAULT_USER_AGENT))) {
      userAgent +=", " + ClientConfiguration.DEFAULT_USER_AGENT;
    }
    connection.setRequestProperty("User-Agent", userAgent);

    return connection;
  }

  private static class TrustingX509TrustManager implements X509TrustManager {
    //~ class properties ======================================================
    private static final X509Certificate[] X_509_CERTIFICATES = new X509Certificate[0];

    //~ class members =========================================================
    @Override
    public void checkClientTrusted(X509Certificate[] x509Certificates, String s)
        throws CertificateException {

    }

    @Override
    public void checkServerTrusted(X509Certificate[] x509Certificates, String s)
        throws CertificateException {
    }

    @Override
    public X509Certificate[] getAcceptedIssuers() {
      return X_509_CERTIFICATES;
    }
  }

  private static class TrustHostnameVerifier implements HostnameVerifier {
    @Override
    public boolean verify(String s, SSLSession sslSession) {
      if (LOG.isLoggable(Level.INFO)) {
        LOG.info("Verify host name: [" + s + "], peer host: [" + sslSession.getPeerHost() + "]");
      }

      return true;
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy