001package io.freefair.spring.okhttp.autoconfigure;
002
003import io.freefair.spring.okhttp.client.OkHttpClientRequestFactory;
004import okhttp3.OkHttpClient;
005import org.springframework.boot.autoconfigure.AutoConfiguration;
006import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
007import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
008import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration;
009import org.springframework.boot.autoconfigure.web.client.RestTemplateAutoConfiguration;
010import org.springframework.boot.autoconfigure.web.client.RestTemplateBuilderConfigurer;
011import org.springframework.boot.ssl.SslBundle;
012import org.springframework.boot.web.client.ClientHttpRequestFactorySettings;
013import org.springframework.boot.web.client.RestTemplateBuilder;
014import org.springframework.boot.web.client.RestTemplateCustomizer;
015import org.springframework.context.annotation.Bean;
016import org.springframework.context.annotation.Conditional;
017import org.springframework.context.annotation.Lazy;
018import org.springframework.http.client.ClientHttpRequestFactory;
019import org.springframework.util.Assert;
020import org.springframework.web.client.RestTemplate;
021import javax.net.ssl.SSLContext;
022import javax.net.ssl.SSLSocketFactory;
023import javax.net.ssl.TrustManager;
024import javax.net.ssl.X509TrustManager;
025import java.time.Duration;
026import java.util.function.Function;
027
028/**
029 * @author Lars Grefer
030 * @see RestTemplateAutoConfiguration
031 */
032@AutoConfiguration(before = RestTemplateAutoConfiguration.class, after = HttpMessageConvertersAutoConfiguration.class)
033@ConditionalOnClass({RestTemplateCustomizer.class, RestTemplate.class, OkHttpClientRequestFactory.class})
034@Conditional(NotReactiveWebApplicationCondition.class)
035public class OkHttpRestTemplateAutoConfiguration {
036    @Bean
037    @Lazy
038    @ConditionalOnMissingBean
039    public RestTemplateBuilder restTemplateBuilder(RestTemplateBuilderConfigurer restTemplateBuilderConfigurer, OkHttpClient okHttpClient) {
040        RestTemplateBuilder builder = new RestTemplateBuilder();
041        builder = builder.requestFactory(new RequestFactoryFunction(okHttpClient));
042        return restTemplateBuilderConfigurer.configure(builder);
043    }
044
045
046    static class RequestFactoryFunction implements Function<ClientHttpRequestFactorySettings, ClientHttpRequestFactory> {
047        private OkHttpClient okHttpClient;
048
049        @Override
050        public ClientHttpRequestFactory apply(ClientHttpRequestFactorySettings settings) {
051            OkHttpClient.Builder builder = okHttpClient.newBuilder();
052            Duration connectTimeout = settings.connectTimeout();
053            if (connectTimeout != null) {
054                builder.connectTimeout(connectTimeout);
055            }
056            Duration readTimeout = settings.readTimeout();
057            if (readTimeout != null) {
058                builder.readTimeout(readTimeout);
059            }
060            SslBundle sslBundle = settings.sslBundle();
061            if (sslBundle != null) {
062                Assert.state(!sslBundle.getOptions().isSpecified(), "SSL Options cannot be specified with OkHttp");
063                SSLContext sslContext = sslBundle.createSslContext();
064                SSLSocketFactory socketFactory = sslContext.getSocketFactory();
065                TrustManager[] trustManagers = sslBundle.getManagers().getTrustManagers();
066                Assert.state(trustManagers.length == 1, "Trust material must be provided in the SSL bundle for OkHttp3ClientHttpRequestFactory");
067                builder.sslSocketFactory(socketFactory, (X509TrustManager) trustManagers[0]);
068            }
069            return new OkHttpClientRequestFactory(builder.build());
070        }
071
072        public RequestFactoryFunction(final OkHttpClient okHttpClient) {
073            this.okHttpClient = okHttpClient;
074        }
075    }
076}