2323import java .util .concurrent .TimeUnit ;
2424import java .util .function .Supplier ;
2525
26+ import javax .net .ssl .SSLSocketFactory ;
27+ import javax .net .ssl .TrustManager ;
28+ import javax .net .ssl .X509TrustManager ;
29+
30+ import okhttp3 .OkHttpClient ;
2631import org .apache .hc .client5 .http .classic .HttpClient ;
2732import org .apache .hc .client5 .http .impl .classic .HttpClientBuilder ;
2833import org .apache .hc .client5 .http .impl .io .PoolingHttpClientConnectionManager ;
2934import org .apache .hc .client5 .http .impl .io .PoolingHttpClientConnectionManagerBuilder ;
35+ import org .apache .hc .client5 .http .ssl .DefaultHostnameVerifier ;
36+ import org .apache .hc .client5 .http .ssl .SSLConnectionSocketFactory ;
3037import org .apache .hc .core5 .http .io .SocketConfig ;
3138
3239import org .springframework .boot .context .properties .PropertyMapper ;
40+ import org .springframework .boot .ssl .SslBundle ;
41+ import org .springframework .boot .ssl .SslOptions ;
3342import org .springframework .http .client .AbstractClientHttpRequestFactoryWrapper ;
3443import org .springframework .http .client .ClientHttpRequestFactory ;
3544import org .springframework .http .client .HttpComponentsClientHttpRequestFactory ;
3645import org .springframework .http .client .OkHttp3ClientHttpRequestFactory ;
3746import org .springframework .http .client .SimpleClientHttpRequestFactory ;
3847import org .springframework .util .Assert ;
3948import org .springframework .util .ClassUtils ;
49+ import org .springframework .util .CollectionUtils ;
4050import org .springframework .util .ReflectionUtils ;
4151
4252/**
4555 *
4656 * @author Andy Wilkinson
4757 * @author Phillip Webb
58+ * @author Scott Frederick
4859 * @since 3.0.0
4960 */
5061public final class ClientHttpRequestFactories {
@@ -134,25 +145,39 @@ private static <T extends ClientHttpRequestFactory> T createRequestFactory(Class
134145 static class HttpComponents {
135146
136147 static HttpComponentsClientHttpRequestFactory get (ClientHttpRequestFactorySettings settings ) {
137- HttpComponentsClientHttpRequestFactory requestFactory = createRequestFactory (settings .readTimeout ());
148+ HttpComponentsClientHttpRequestFactory requestFactory = createRequestFactory (settings .readTimeout (),
149+ settings .sslBundle ());
138150 PropertyMapper map = PropertyMapper .get ().alwaysApplyingWhenNonNull ();
139151 map .from (settings ::connectTimeout ).asInt (Duration ::toMillis ).to (requestFactory ::setConnectTimeout );
140152 map .from (settings ::bufferRequestBody ).to (requestFactory ::setBufferRequestBody );
141153 return requestFactory ;
142154 }
143155
144- private static HttpComponentsClientHttpRequestFactory createRequestFactory (Duration readTimeout ) {
145- return ( readTimeout != null ) ? new HttpComponentsClientHttpRequestFactory ( createHttpClient ( readTimeout ))
146- : new HttpComponentsClientHttpRequestFactory ();
156+ private static HttpComponentsClientHttpRequestFactory createRequestFactory (Duration readTimeout ,
157+ SslBundle sslBundle ) {
158+ return new HttpComponentsClientHttpRequestFactory (createHttpClient ( readTimeout , sslBundle ) );
147159 }
148160
149- private static HttpClient createHttpClient (Duration readTimeout ) {
150- SocketConfig socketConfig = SocketConfig .custom ()
151- .setSoTimeout ((int ) readTimeout .toMillis (), TimeUnit .MILLISECONDS )
152- .build ();
153- PoolingHttpClientConnectionManager connectionManager = PoolingHttpClientConnectionManagerBuilder .create ()
154- .setDefaultSocketConfig (socketConfig )
155- .build ();
161+ private static HttpClient createHttpClient (Duration readTimeout , SslBundle sslBundle ) {
162+ PoolingHttpClientConnectionManagerBuilder connectionManagerBuilder = PoolingHttpClientConnectionManagerBuilder
163+ .create ();
164+ if (readTimeout != null ) {
165+ SocketConfig socketConfig = SocketConfig .custom ()
166+ .setSoTimeout ((int ) readTimeout .toMillis (), TimeUnit .MILLISECONDS )
167+ .build ();
168+ connectionManagerBuilder .setDefaultSocketConfig (socketConfig );
169+ }
170+ if (sslBundle != null ) {
171+ SslOptions options = sslBundle .getOptions ();
172+ String [] enabledProtocols = (!CollectionUtils .isEmpty (options .getEnabledProtocols ()))
173+ ? options .getEnabledProtocols ().toArray (String []::new ) : null ;
174+ String [] ciphers = (!CollectionUtils .isEmpty (options .getCiphers ()))
175+ ? options .getCiphers ().toArray (String []::new ) : null ;
176+ SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory (sslBundle .createSslContext (),
177+ enabledProtocols , ciphers , new DefaultHostnameVerifier ());
178+ connectionManagerBuilder .setSSLSocketFactory (socketFactory );
179+ }
180+ PoolingHttpClientConnectionManager connectionManager = connectionManagerBuilder .build ();
156181 return HttpClientBuilder .create ().setConnectionManager (connectionManager ).build ();
157182 }
158183
@@ -166,13 +191,27 @@ static class OkHttp {
166191 static OkHttp3ClientHttpRequestFactory get (ClientHttpRequestFactorySettings settings ) {
167192 Assert .state (settings .bufferRequestBody () == null ,
168193 () -> "OkHttp3ClientHttpRequestFactory does not support request body buffering" );
169- OkHttp3ClientHttpRequestFactory requestFactory = new OkHttp3ClientHttpRequestFactory ( );
194+ OkHttp3ClientHttpRequestFactory requestFactory = createRequestFactory ( settings . sslBundle () );
170195 PropertyMapper map = PropertyMapper .get ().alwaysApplyingWhenNonNull ();
171196 map .from (settings ::connectTimeout ).asInt (Duration ::toMillis ).to (requestFactory ::setConnectTimeout );
172197 map .from (settings ::readTimeout ).asInt (Duration ::toMillis ).to (requestFactory ::setReadTimeout );
173198 return requestFactory ;
174199 }
175200
201+ private static OkHttp3ClientHttpRequestFactory createRequestFactory (SslBundle sslBundle ) {
202+ if (sslBundle != null ) {
203+ SSLSocketFactory socketFactory = sslBundle .createSslContext ().getSocketFactory ();
204+ TrustManager [] trustManagers = sslBundle .getManagers ().getTrustManagers ();
205+ Assert .state (trustManagers .length == 1 ,
206+ "Trust material must be provided in the SSL bundle for OkHttp3ClientHttpRequestFactory" );
207+ OkHttpClient client = new OkHttpClient .Builder ()
208+ .sslSocketFactory (socketFactory , (X509TrustManager ) trustManagers [0 ])
209+ .build ();
210+ return new OkHttp3ClientHttpRequestFactory (client );
211+ }
212+ return new OkHttp3ClientHttpRequestFactory ();
213+ }
214+
176215 }
177216
178217 /**
0 commit comments