2323import java .util .List ;
2424import java .util .concurrent .TimeUnit ;
2525import java .util .function .Consumer ;
26+ import java .util .function .Function ;
2627
2728import org .apache .hc .client5 .http .classic .HttpClient ;
2829import org .apache .hc .client5 .http .impl .DefaultRedirectStrategy ;
3233import org .apache .hc .client5 .http .protocol .RedirectStrategy ;
3334import org .apache .hc .client5 .http .ssl .DefaultClientTlsStrategy ;
3435import org .apache .hc .client5 .http .ssl .DefaultHostnameVerifier ;
36+ import org .apache .hc .client5 .http .ssl .TlsSocketStrategy ;
3537import org .apache .hc .core5 .http .HttpRequest ;
3638import org .apache .hc .core5 .http .HttpResponse ;
3739import org .apache .hc .core5 .http .io .SocketConfig ;
4244import org .springframework .boot .ssl .SslBundle ;
4345import org .springframework .boot .ssl .SslOptions ;
4446import org .springframework .http .client .HttpComponentsClientHttpRequestFactory ;
47+ import org .springframework .util .Assert ;
4548import org .springframework .util .ClassUtils ;
4649
4750/**
5558public final class HttpComponentsClientHttpRequestFactoryBuilder
5659 extends AbstractClientHttpRequestFactoryBuilder <HttpComponentsClientHttpRequestFactory > {
5760
61+ private final Consumer <HttpClientBuilder > httpClientCustomizer ;
62+
63+ private final Consumer <PoolingHttpClientConnectionManagerBuilder > connectionManagerCustomizer ;
64+
65+ private final Consumer <SocketConfig .Builder > socketConfigCustomizer ;
66+
67+ private final Function <SslBundle , TlsSocketStrategy > tlsSocketStrategyFactory ;
68+
5869 HttpComponentsClientHttpRequestFactoryBuilder () {
59- this (Collections .emptyList ());
70+ this (Collections .emptyList (), emptyCustomizer (), emptyCustomizer (), emptyCustomizer (),
71+ HttpComponentsClientHttpRequestFactoryBuilder ::createTlsSocketStrategy );
6072 }
6173
6274 private HttpComponentsClientHttpRequestFactoryBuilder (
63- List <Consumer <HttpComponentsClientHttpRequestFactory >> customizers ) {
75+ List <Consumer <HttpComponentsClientHttpRequestFactory >> customizers ,
76+ Consumer <HttpClientBuilder > httpClientCustomizer ,
77+ Consumer <PoolingHttpClientConnectionManagerBuilder > connectionManagerCustomizer ,
78+ Consumer <SocketConfig .Builder > socketConfigCustomizer ,
79+ Function <SslBundle , TlsSocketStrategy > tlsSocketStrategyFactory ) {
6480 super (customizers );
81+ this .httpClientCustomizer = httpClientCustomizer ;
82+ this .connectionManagerCustomizer = connectionManagerCustomizer ;
83+ this .socketConfigCustomizer = socketConfigCustomizer ;
84+ this .tlsSocketStrategyFactory = tlsSocketStrategyFactory ;
6585 }
6686
6787 @ Override
6888 public HttpComponentsClientHttpRequestFactoryBuilder withCustomizer (
6989 Consumer <HttpComponentsClientHttpRequestFactory > customizer ) {
70- return new HttpComponentsClientHttpRequestFactoryBuilder (mergedCustomizers (customizer ));
90+ return new HttpComponentsClientHttpRequestFactoryBuilder (mergedCustomizers (customizer ),
91+ this .httpClientCustomizer , this .connectionManagerCustomizer , this .socketConfigCustomizer ,
92+ this .tlsSocketStrategyFactory );
7193 }
7294
7395 @ Override
7496 public HttpComponentsClientHttpRequestFactoryBuilder withCustomizers (
7597 Collection <Consumer <HttpComponentsClientHttpRequestFactory >> customizers ) {
76- return new HttpComponentsClientHttpRequestFactoryBuilder (mergedCustomizers (customizers ));
98+ return new HttpComponentsClientHttpRequestFactoryBuilder (mergedCustomizers (customizers ),
99+ this .httpClientCustomizer , this .connectionManagerCustomizer , this .socketConfigCustomizer ,
100+ this .tlsSocketStrategyFactory );
101+ }
102+
103+ /**
104+ * Return a new {@link HttpComponentsClientHttpRequestFactoryBuilder} that applies
105+ * additional customization to the underlying {@link HttpClientBuilder}.
106+ * @param httpClientCustomizer the customizer to apply
107+ * @return a new {@link HttpComponentsClientHttpRequestFactoryBuilder} instance
108+ */
109+ public HttpComponentsClientHttpRequestFactoryBuilder withHttpClientCustomizer (
110+ Consumer <HttpClientBuilder > httpClientCustomizer ) {
111+ Assert .notNull (httpClientCustomizer , "'httpClientCustomizer' must not be null" );
112+ return new HttpComponentsClientHttpRequestFactoryBuilder (getCustomizers (),
113+ this .httpClientCustomizer .andThen (httpClientCustomizer ), this .connectionManagerCustomizer ,
114+ this .socketConfigCustomizer , this .tlsSocketStrategyFactory );
115+ }
116+
117+ /**
118+ * Return a new {@link HttpComponentsClientHttpRequestFactoryBuilder} that applies
119+ * additional customization to the underlying
120+ * {@link PoolingHttpClientConnectionManagerBuilder}.
121+ * @param connectionManagerCustomizer the customizer to apply
122+ * @return a new {@link HttpComponentsClientHttpRequestFactoryBuilder} instance
123+ */
124+ public HttpComponentsClientHttpRequestFactoryBuilder withConnectionManagerCustomizer (
125+ Consumer <PoolingHttpClientConnectionManagerBuilder > connectionManagerCustomizer ) {
126+ Assert .notNull (connectionManagerCustomizer , "'connectionManagerCustomizer' must not be null" );
127+ return new HttpComponentsClientHttpRequestFactoryBuilder (getCustomizers (), this .httpClientCustomizer ,
128+ this .connectionManagerCustomizer .andThen (connectionManagerCustomizer ), this .socketConfigCustomizer ,
129+ this .tlsSocketStrategyFactory );
130+ }
131+
132+ /**
133+ * Return a new {@link HttpComponentsClientHttpRequestFactoryBuilder} that applies
134+ * additional customization to the underlying
135+ * {@link org.apache.hc.core5.http.io.SocketConfig.Builder}.
136+ * @param socketConfigCustomizer the customizer to apply
137+ * @return a new {@link HttpComponentsClientHttpRequestFactoryBuilder} instance
138+ */
139+ public HttpComponentsClientHttpRequestFactoryBuilder withSocketConfigCustomizer (
140+ Consumer <SocketConfig .Builder > socketConfigCustomizer ) {
141+ Assert .notNull (socketConfigCustomizer , "'socketConfigCustomizer' must not be null" );
142+ return new HttpComponentsClientHttpRequestFactoryBuilder (getCustomizers (), this .httpClientCustomizer ,
143+ this .connectionManagerCustomizer , this .socketConfigCustomizer .andThen (socketConfigCustomizer ),
144+ this .tlsSocketStrategyFactory );
145+ }
146+
147+ /**
148+ * Return a new {@link HttpComponentsClientHttpRequestFactoryBuilder} with a
149+ * replacement {@link TlsSocketStrategy} factory.
150+ * @param tlsSocketStrategyFactory the new factory used to create a
151+ * {@link TlsSocketStrategy} for a given {@link SslBundle}
152+ * @return a new {@link HttpComponentsClientHttpRequestFactoryBuilder} instance
153+ */
154+ public HttpComponentsClientHttpRequestFactoryBuilder withTlsSocketStrategyFactory (
155+ Function <SslBundle , TlsSocketStrategy > tlsSocketStrategyFactory ) {
156+ Assert .notNull (tlsSocketStrategyFactory , "'tlsSocketStrategyFactory' must not be null" );
157+ return new HttpComponentsClientHttpRequestFactoryBuilder (getCustomizers (), this .httpClientCustomizer ,
158+ this .connectionManagerCustomizer , this .socketConfigCustomizer , tlsSocketStrategyFactory );
77159 }
78160
79161 @ Override
@@ -87,11 +169,12 @@ protected HttpComponentsClientHttpRequestFactory createClientHttpRequestFactory(
87169 }
88170
89171 private HttpClient createHttpClient (ClientHttpRequestFactorySettings settings ) {
90- return HttpClientBuilder .create ()
172+ HttpClientBuilder builder = HttpClientBuilder .create ()
91173 .useSystemProperties ()
92174 .setRedirectStrategy (asRedirectStrategy (settings .redirects ()))
93- .setConnectionManager (createConnectionManager (settings ))
94- .build ();
175+ .setConnectionManager (createConnectionManager (settings ));
176+ this .httpClientCustomizer .accept (builder );
177+ return builder .build ();
95178 }
96179
97180 private RedirectStrategy asRedirectStrategy (Redirects redirects ) {
@@ -102,23 +185,31 @@ private RedirectStrategy asRedirectStrategy(Redirects redirects) {
102185 }
103186
104187 private PoolingHttpClientConnectionManager createConnectionManager (ClientHttpRequestFactorySettings settings ) {
105- PoolingHttpClientConnectionManagerBuilder builder = PoolingHttpClientConnectionManagerBuilder .create ();
188+ PoolingHttpClientConnectionManagerBuilder builder = PoolingHttpClientConnectionManagerBuilder .create ()
189+ .useSystemProperties ();
190+ PropertyMapper map = PropertyMapper .get ().alwaysApplyingWhenNonNull ();
191+ builder .setDefaultSocketConfig (createSocketConfig (settings ));
192+ map .from (settings ::sslBundle ).as (this .tlsSocketStrategyFactory ).to (builder ::setTlsSocketStrategy );
193+ this .connectionManagerCustomizer .accept (builder );
194+ return builder .build ();
195+ }
196+
197+ private SocketConfig createSocketConfig (ClientHttpRequestFactorySettings settings ) {
198+ SocketConfig .Builder builder = SocketConfig .custom ();
106199 PropertyMapper map = PropertyMapper .get ().alwaysApplyingWhenNonNull ();
107- map .from (settings ::readTimeout ).as (this ::createSocketConfig ).to (builder ::setDefaultSocketConfig );
108- map .from (settings ::sslBundle ).as (this ::createTlsSocketStrategy ).to (builder ::setTlsSocketStrategy );
109- return builder .useSystemProperties ().build ();
200+ map .from (settings ::readTimeout )
201+ .asInt (Duration ::toMillis )
202+ .to ((timeout ) -> builder .setSoTimeout (timeout , TimeUnit .MILLISECONDS ));
203+ this .socketConfigCustomizer .accept (builder );
204+ return builder .build ();
110205 }
111206
112- private DefaultClientTlsStrategy createTlsSocketStrategy (SslBundle sslBundle ) {
207+ private static TlsSocketStrategy createTlsSocketStrategy (SslBundle sslBundle ) {
113208 SslOptions options = sslBundle .getOptions ();
114209 return new DefaultClientTlsStrategy (sslBundle .createSslContext (), options .getEnabledProtocols (),
115210 options .getCiphers (), null , new DefaultHostnameVerifier ());
116211 }
117212
118- private SocketConfig createSocketConfig (Duration readTimeout ) {
119- return SocketConfig .custom ().setSoTimeout ((int ) readTimeout .toMillis (), TimeUnit .MILLISECONDS ).build ();
120- }
121-
122213 /**
123214 * {@link RedirectStrategy} that never follows redirects.
124215 */
0 commit comments