001package io.freefair.spring.okhttp.autoconfigure;
002
003import io.freefair.spring.okhttp.client.OkHttpClientRequestFactory;
004import okhttp3.ConnectionSpec;
005import okhttp3.OkHttpClient;
006import org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder;
007import org.springframework.boot.http.client.ClientHttpRequestFactorySettings;
008import org.springframework.boot.ssl.SslBundle;
009import org.springframework.boot.ssl.SslOptions;
010import org.springframework.lang.Nullable;
011import org.springframework.util.Assert;
012import javax.net.ssl.SSLContext;
013import javax.net.ssl.SSLSocketFactory;
014import javax.net.ssl.TrustManager;
015import javax.net.ssl.X509TrustManager;
016import java.time.Duration;
017import java.util.List;
018
019/**
020 * @author Lars Grefer
021 */
022public class OkHttpClientRequestFactoryBuilder implements ClientHttpRequestFactoryBuilder<OkHttpClientRequestFactory> {
023    private final OkHttpClient okHttpClient;
024
025    @Override
026    public OkHttpClientRequestFactory build() {
027        return this.build(null);
028    }
029
030    @Override
031    public OkHttpClientRequestFactory build(@Nullable ClientHttpRequestFactorySettings settings) {
032        OkHttpClient.Builder builder = okHttpClient.newBuilder();
033        if (settings == null) {
034            return new OkHttpClientRequestFactory(builder.build());
035        }
036        Duration connectTimeout = settings.connectTimeout();
037        if (connectTimeout != null) {
038            builder.connectTimeout(connectTimeout);
039        }
040        Duration readTimeout = settings.readTimeout();
041        if (readTimeout != null) {
042            builder.readTimeout(readTimeout);
043        }
044        SslBundle sslBundle = settings.sslBundle();
045        if (sslBundle != null) {
046            SslOptions sslOptions = sslBundle.getOptions();
047            if (sslOptions.isSpecified()) {
048                ConnectionSpec connectionSpec = new ConnectionSpec.Builder(true).cipherSuites(sslOptions.getCiphers()).tlsVersions(sslOptions.getEnabledProtocols()).build();
049                builder.connectionSpecs(List.of(connectionSpec));
050            }
051            SSLContext sslContext = sslBundle.createSslContext();
052            SSLSocketFactory socketFactory = sslContext.getSocketFactory();
053            TrustManager[] trustManagers = sslBundle.getManagers().getTrustManagers();
054            Assert.state(trustManagers.length == 1, "Trust material must be provided in the SSL bundle for OkHttp3ClientHttpRequestFactory");
055            builder.sslSocketFactory(socketFactory, (X509TrustManager) trustManagers[0]);
056        }
057        ClientHttpRequestFactorySettings.Redirects redirects = settings.redirects();
058        if (redirects != null) {
059            switch (redirects) {
060                case FOLLOW_WHEN_POSSIBLE, FOLLOW -> {
061                    builder.followRedirects(true);
062                    builder.followSslRedirects(true);
063                }
064                case DONT_FOLLOW -> {
065                    builder.followRedirects(false);
066                    builder.followSslRedirects(true);
067                }
068                default -> {
069                }
070            }
071        }
072        return new OkHttpClientRequestFactory(builder.build());
073    }
074
075    public OkHttpClientRequestFactoryBuilder(final OkHttpClient okHttpClient) {
076        this.okHttpClient = okHttpClient;
077    }
078}