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

co.cask.common.http.HttpRequests Maven / Gradle / Ivy

/*
 * Copyright © 2014 Cask Data, Inc.
 *
 * 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 co.cask.common.http;

import com.google.common.collect.Multimap;
import com.google.common.io.ByteStreams;
import com.google.common.io.InputSupplier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

/**
 * Executes {@link HttpRequest}s and returns an {@link HttpResponse}.
 */
public final class HttpRequests {
  private static final Logger LOG = LoggerFactory.getLogger(HttpRequests.class);

  private static final AtomicReference TRUST_ALL_SSL_FACTORY =
    new AtomicReference();

  private HttpRequests() { }

  /**
   * Executes an HTTP request to the url provided.
   *
   * @param request HTTP request to execute
   * @param requestConfig configuration for the HTTP request to execute
   * @return HTTP response
   */
  public static HttpResponse execute(HttpRequest request, HttpRequestConfig requestConfig) throws IOException {
    String requestMethod = request.getMethod().name();
    URL url = request.getURL();

    HttpURLConnection conn = (HttpURLConnection) url.openConnection();
    conn.setRequestMethod(requestMethod);
    conn.setReadTimeout(requestConfig.getReadTimeout());
    conn.setConnectTimeout(requestConfig.getConnectTimeout());

    Multimap headers = request.getHeaders();
    if (headers != null && !headers.isEmpty()) {
      for (Map.Entry header : headers.entries()) {
        conn.setRequestProperty(header.getKey(), header.getValue());
      }
    }

    InputSupplier bodySrc = request.getBody();
    if (bodySrc != null) {
      conn.setDoOutput(true);
      Long bodyLength = request.getBodyLength();
      if (bodyLength != null) {
        // use intValue to support 1.6
        if (bodyLength > requestConfig.getFixedLengthStreamingThreshold()) {
          conn.setFixedLengthStreamingMode(bodyLength.intValue());
        }
      } else {
        conn.setChunkedStreamingMode(0);
      }
    }

    if (conn instanceof HttpsURLConnection && !requestConfig.isVerifySSLCert()) {
      // Certificate checks are disabled for HTTPS connection.
      LOG.debug("Disabling SSL certificate check for {}", request.getURL());
      try {
        disableCertCheck((HttpsURLConnection) conn);
      } catch (Exception e) {
        LOG.error("Got exception while disabling SSL certificate check for {}", request.getURL());
      }
    }

    conn.connect();

    try {
      if (bodySrc != null) {
        OutputStream os = conn.getOutputStream();
        try {
          ByteStreams.copy(bodySrc, os);
        } finally {
          os.close();
        }
      }

      try {
        if (isSuccessful(conn.getResponseCode())) {
          return new HttpResponse(conn.getResponseCode(), conn.getResponseMessage(),
                                  ByteStreams.toByteArray(conn.getInputStream()), conn.getHeaderFields());
        }
      } catch (FileNotFoundException e) {
        // Server returns 404. Hence handle as error flow below. Intentional having empty catch block.
      }

      // Non 2xx response
      InputStream es = conn.getErrorStream();
      byte[] content = (es == null) ? new byte[0] : ByteStreams.toByteArray(es);
      return new HttpResponse(conn.getResponseCode(), conn.getResponseMessage(), content, conn.getHeaderFields());
    } finally {
      conn.disconnect();
    }
  }

  /**
   * Executes an HTTP request with default request configuration.
   *
   * @param request HTTP request to execute
   * @return HTTP response
   * @throws java.io.IOException
   */
  public static HttpResponse execute(HttpRequest request) throws IOException {
    return execute(request, HttpRequestConfig.DEFAULT);
  }

  private static boolean isSuccessful(int responseCode) {
    return 200 <= responseCode && responseCode < 300;
  }

  public static void disableCertCheck(HttpsURLConnection conn)
    throws NoSuchAlgorithmException, KeyManagementException {
    if (TRUST_ALL_SSL_FACTORY.get() == null) {
      SSLContext sslContext = SSLContext.getInstance("SSL");
      sslContext.init(null, new TrustManager[]{
        new X509TrustManager() {
          @Override
          public X509Certificate[] getAcceptedIssuers() {
            return new X509Certificate[0];
          }

          @Override
          public void checkClientTrusted(X509Certificate[] x509Certificates, String s)
            throws CertificateException {
            // Trust all
          }

          @Override
          public void checkServerTrusted(X509Certificate[] x509Certificates, String s)
            throws CertificateException {
            // Trust all
          }
        }
      }, new SecureRandom());

      TRUST_ALL_SSL_FACTORY.compareAndSet(null, sslContext.getSocketFactory());
    }

    conn.setSSLSocketFactory(TRUST_ALL_SSL_FACTORY.get());
    conn.setHostnameVerifier(TRUST_ALL_HOSTNAME_VERIFIER);
  }

  private static final HostnameVerifier TRUST_ALL_HOSTNAME_VERIFIER =
    new HostnameVerifier() {
      @Override
      public boolean verify(String hostname, SSLSession session) {
        return true;
      }
    };
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy