001package dk.netarkivet.common.utils;
002
003import org.apache.http.config.Registry;
004import org.apache.http.config.RegistryBuilder;
005import org.apache.http.conn.socket.ConnectionSocketFactory;
006import org.apache.http.conn.ssl.DefaultHostnameVerifier;
007import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
008import org.apache.http.impl.client.CloseableHttpClient;
009import org.apache.http.impl.client.HttpClientBuilder;
010import org.apache.http.impl.client.HttpClients;
011import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
012
013import dk.netarkivet.common.CommonSettings;
014
015/** Class for providing configured HTTPS clients to execute requests over SSL. */
016public class HttpsClientBuilder {
017    private final HttpClientBuilder clientBuilder;
018    private final BasicTwoWaySSLProvider sslProvider;
019
020    /**
021     * Constructor that sets up the whole SSL connection when called.
022     * Simply use {@link #getHttpsClient()} to get a configured client.
023     *
024     * @param privateKeyFile The path to the private key file to use for authentication.
025     */
026    public HttpsClientBuilder(String privateKeyFile) {
027        clientBuilder = HttpClients.custom();
028        sslProvider = new BasicTwoWaySSLProvider(privateKeyFile);
029
030        setupConnection();
031    }
032
033    /**
034     * Sets up the SSL socket and the connection manager and configures the client builder to use them.
035     */
036    private void setupConnection() {
037        SSLConnectionSocketFactory sslsf =
038                new SSLConnectionSocketFactory(sslProvider.getSSLContext(), new DefaultHostnameVerifier());
039        Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory> create()
040                .register("https", sslsf) //register http also?
041                .build();
042        PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
043        configureMaxConnections(cm);
044        clientBuilder.setConnectionManager(cm);
045    }
046
047    /**
048     * Configure the connection managers max connections from settings.
049     * @param cm Connection manager to configure.
050     */
051    private void configureMaxConnections(PoolingHttpClientConnectionManager cm) {
052        cm.setMaxTotal(Settings.getInt(CommonSettings.MAX_TOTAL_CONNECTIONS));
053        cm.setDefaultMaxPerRoute(Settings.getInt(CommonSettings.MAX_CONNECTIONS_PER_ROUTE));
054    }
055
056    /**
057     * Build and deliver the client.
058     * @return An HTTPS client to carry out requests over SSL.
059     */
060    public CloseableHttpClient getHttpsClient() {
061        return clientBuilder.build();
062    }
063}