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

com.teamscale.client.HttpUtils Maven / Gradle / Ivy

Go to download

A tiny service client that only supports Teamscale's the external upload interface and impacted-tests service.

There is a newer version: 34.2.0
Show newest version
package com.teamscale.client;

import okhttp3.Authenticator;
import okhttp3.Credentials;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.ResponseBody;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import retrofit2.Response;
import retrofit2.Retrofit;

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;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.security.GeneralSecurityException;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.time.Duration;
import java.util.Base64;
import java.util.function.Consumer;

/**
 * Utility functions to set up {@link Retrofit} and {@link OkHttpClient}.
 */
public class HttpUtils {

	private static final Logger LOGGER = LoggerFactory.getLogger(HttpUtils.class);

	/**
	 * Default read timeout in seconds.
	 */
	public static final Duration DEFAULT_READ_TIMEOUT = Duration.ofSeconds(60);

	/**
	 * Default write timeout in seconds.
	 */
	public static final Duration DEFAULT_WRITE_TIMEOUT = Duration.ofSeconds(60);

	/**
	 * HTTP header used for authenticating against a proxy server
	 */
	public static final String PROXY_AUTHORIZATION_HTTP_HEADER = "Proxy-Authorization";

	/** Controls whether {@link OkHttpClient}s built with this class will validate SSL certificates. */
	private static boolean shouldValidateSsl = true;

	/** @see #shouldValidateSsl */
	public static void setShouldValidateSsl(boolean shouldValidateSsl) {
		HttpUtils.shouldValidateSsl = shouldValidateSsl;
	}

	/**
	 * Creates a new {@link Retrofit} with proper defaults. The instance and the corresponding {@link OkHttpClient} can
	 * be customized with the given action. Read and write timeouts are set according to the default values.
	 */
	public static Retrofit createRetrofit(Consumer retrofitBuilderAction,
										  Consumer okHttpBuilderAction) {
		return createRetrofit(retrofitBuilderAction, okHttpBuilderAction, DEFAULT_READ_TIMEOUT, DEFAULT_WRITE_TIMEOUT);
	}

	/**
	 * Creates a new {@link Retrofit} with proper defaults. The instance and the corresponding {@link OkHttpClient} can
	 * be customized with the given action. Timeouts for reading and writing can be customized.
	 */
	public static Retrofit createRetrofit(Consumer retrofitBuilderAction,
										  Consumer okHttpBuilderAction, Duration readTimeout,
										  Duration writeTimeout) {
		OkHttpClient.Builder httpClientBuilder = new OkHttpClient.Builder();
		setTimeouts(httpClientBuilder, readTimeout, writeTimeout);
		setUpSslValidation(httpClientBuilder);
		setUpProxyServer(httpClientBuilder);
		okHttpBuilderAction.accept(httpClientBuilder);

		Retrofit.Builder builder = new Retrofit.Builder().client(httpClientBuilder.build());
		retrofitBuilderAction.accept(builder);
		return builder.build();
	}

	/**
	 * Java and/or OkHttp do not pick up the http.proxy* and https.proxy* system properties reliably. We need to teach
	 * OkHttp to always pick them up.
	 * 

* Sources: https://memorynotfound.com/configure-http-proxy-settings-java/ * & * https://stackoverflow.com/a/35567936 */ private static void setUpProxyServer(OkHttpClient.Builder httpClientBuilder) { boolean setHttpsProxyWasSuccessful = setUpProxyServerForProtocol(ProxySystemProperties.Protocol.HTTPS, httpClientBuilder); if (!setHttpsProxyWasSuccessful) { setUpProxyServerForProtocol(ProxySystemProperties.Protocol.HTTP, httpClientBuilder); } } private static boolean setUpProxyServerForProtocol(ProxySystemProperties.Protocol protocol, OkHttpClient.Builder httpClientBuilder) { ProxySystemProperties proxySystemProperties = new ProxySystemProperties(protocol); String proxyHost = proxySystemProperties.getProxyHost(); int proxyPort = proxySystemProperties.getProxyPort(); String proxyUser = proxySystemProperties.getProxyUser(); String proxyPassword = proxySystemProperties.getProxyPassword(); if (proxySystemProperties.proxyServerIsSet()) { useProxyServer(httpClientBuilder, proxyHost, proxyPort); if (proxySystemProperties.proxyAuthIsSet()) { useProxyAuthenticator(httpClientBuilder, proxyUser, proxyPassword); } return true; } return false; } private static void useProxyServer(OkHttpClient.Builder httpClientBuilder, String proxyHost, int proxyPort) { httpClientBuilder.proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyHost, proxyPort))); } private static void useProxyAuthenticator(OkHttpClient.Builder httpClientBuilder, String user, String password) { Authenticator proxyAuthenticator = (route, response) -> { String credential = Credentials.basic(user, password); return response.request().newBuilder() .header(PROXY_AUTHORIZATION_HTTP_HEADER, credential) .build(); }; httpClientBuilder.proxyAuthenticator(proxyAuthenticator); } /** * Sets sensible defaults for the {@link OkHttpClient}. */ private static void setTimeouts(OkHttpClient.Builder builder, Duration readTimeout, Duration writeTimeout) { builder.connectTimeout(Duration.ofSeconds(60)); builder.readTimeout(readTimeout); builder.writeTimeout(writeTimeout); } /** * Enables or disables SSL certificate validation for the {@link Retrofit} instance */ private static void setUpSslValidation(OkHttpClient.Builder builder) { if (shouldValidateSsl) { // this is the default behaviour of OkHttp, so we don't need to do anything return; } SSLSocketFactory sslSocketFactory; try { SSLContext sslContext = SSLContext.getInstance("TLS"); sslContext.init(null, new TrustManager[]{TrustAllCertificatesManager.INSTANCE}, new SecureRandom()); sslSocketFactory = sslContext.getSocketFactory(); } catch (GeneralSecurityException e) { LOGGER.error("Could not disable SSL certificate validation. Leaving it enabled", e); return; } // this causes OkHttp to accept all certificates builder.sslSocketFactory(sslSocketFactory, TrustAllCertificatesManager.INSTANCE); // this causes it to ignore invalid host names in the certificates builder.hostnameVerifier((String hostName, SSLSession session) -> true); } /** * A simple implementation of {@link X509TrustManager} that simple trusts every certificate. */ public static class TrustAllCertificatesManager implements X509TrustManager { /** Singleton instance. */ /*package*/ static final TrustAllCertificatesManager INSTANCE = new TrustAllCertificatesManager(); /** Returns null. */ @Override public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; } /** Does nothing. */ @Override public void checkServerTrusted(X509Certificate[] certs, String authType) { // Nothing to do } /** Does nothing. */ @Override public void checkClientTrusted(X509Certificate[] certs, String authType) { // Nothing to do } } /** * Returns the error body of the given response or a replacement string in case it is null. */ public static String getErrorBodyStringSafe(Response response) throws IOException { ResponseBody errorBody = response.errorBody(); if (errorBody == null) { return ""; } return errorBody.string(); } /** * Returns an interceptor, which adds a basic auth header to a request. */ public static Interceptor getBasicAuthInterceptor(String username, String password) { String credentials = username + ":" + password; String basic = "Basic " + Base64.getEncoder().encodeToString(credentials.getBytes()); return chain -> { Request newRequest = chain.request().newBuilder().header("Authorization", basic).build(); return chain.proceed(newRequest); }; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy