1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.kuali.rice.ksb.messaging.serviceconnectors;
17
18 import org.apache.http.client.HttpRequestRetryHandler;
19 import org.apache.http.client.config.CookieSpecs;
20 import org.apache.http.client.config.RequestConfig;
21 import org.apache.http.config.ConnectionConfig;
22 import org.apache.http.config.Registry;
23 import org.apache.http.config.RegistryBuilder;
24 import org.apache.http.config.SocketConfig;
25 import org.apache.http.conn.HttpClientConnectionManager;
26 import org.apache.http.conn.socket.ConnectionSocketFactory;
27 import org.apache.http.conn.socket.PlainConnectionSocketFactory;
28 import org.apache.http.conn.ssl.AllowAllHostnameVerifier;
29 import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
30 import org.apache.http.conn.ssl.SSLContextBuilder;
31 import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
32 import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
33 import org.apache.http.impl.client.HttpClientBuilder;
34 import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
35 import org.kuali.rice.core.api.config.property.ConfigContext;
36 import org.kuali.rice.core.api.exception.RiceRuntimeException;
37 import org.kuali.rice.ksb.util.KSBConstants;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
40 import org.springframework.beans.factory.InitializingBean;
41
42 import java.nio.charset.Charset;
43 import java.security.KeyManagementException;
44 import java.security.KeyStoreException;
45 import java.security.NoSuchAlgorithmException;
46 import java.util.Arrays;
47 import java.util.HashSet;
48 import java.util.Map;
49 import java.util.Set;
50
51 import static org.kuali.rice.ksb.messaging.serviceconnectors.HttpClientParams.*;
52
53
54
55
56
57
58
59
60
61
62
63
64 public class DefaultHttpClientConfigurer implements HttpClientConfigurer, InitializingBean {
65
66 static final Logger LOG = LoggerFactory.getLogger(DefaultHttpClientConfigurer.class);
67
68 private static final String RETRY_SOCKET_EXCEPTION_PROPERTY = "ksb.thinClient.retrySocketException";
69 private static final int DEFAULT_SOCKET_TIMEOUT = 2 * 60 * 1000;
70
71
72
73
74 private static final int DEFAULT_MAX_TOTAL_CONNECTIONS = 20;
75
76
77 private static final Set<String> unsupportedParamsWhitelist =
78 new HashSet<String>(Arrays.asList("http.port", "http.service.url"));
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96 @Override
97 public void customizeHttpClient(HttpClientBuilder httpClientBuilder) {
98
99 HttpClientConnectionManager connectionManager = buildConnectionManager();
100 if (connectionManager != null) {
101 httpClientBuilder.setConnectionManager(connectionManager);
102 }
103
104 RequestConfig requestConfig = buildRequestConfig();
105 if (requestConfig != null) {
106 httpClientBuilder.setDefaultRequestConfig(requestConfig);
107 }
108
109 HttpRequestRetryHandler retryHandler = buildRetryHandler();
110 if (retryHandler != null) {
111 httpClientBuilder.setRetryHandler(retryHandler);
112 }
113 }
114
115
116
117
118
119
120
121
122
123 protected HttpClientConnectionManager buildConnectionManager() {
124 PoolingHttpClientConnectionManager poolingConnectionManager = null;
125
126 SSLConnectionSocketFactory sslConnectionSocketFactory = buildSslConnectionSocketFactory();
127 if (sslConnectionSocketFactory != null) {
128 Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder
129 .<ConnectionSocketFactory> create().register("https", sslConnectionSocketFactory)
130 .register("http", new PlainConnectionSocketFactory())
131 .build();
132 poolingConnectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
133 } else {
134 poolingConnectionManager = new PoolingHttpClientConnectionManager();
135 }
136
137
138 poolingConnectionManager.setMaxTotal(MAX_TOTAL_CONNECTIONS.getValueOrDefault(DEFAULT_MAX_TOTAL_CONNECTIONS));
139
140
141 poolingConnectionManager.setDefaultMaxPerRoute(MAX_TOTAL_CONNECTIONS.getValueOrDefault(DEFAULT_MAX_TOTAL_CONNECTIONS));
142
143
144 SocketConfig.Builder socketConfigBuilder = SocketConfig.custom();
145 socketConfigBuilder.setSoTimeout(SO_TIMEOUT.getValueOrDefault(DEFAULT_SOCKET_TIMEOUT));
146
147 Integer soLinger = SO_LINGER.getValue();
148 if (soLinger != null) {
149 socketConfigBuilder.setSoLinger(soLinger);
150 }
151
152 Boolean isTcpNoDelay = TCP_NODELAY.getValue();
153 if (isTcpNoDelay != null) {
154 socketConfigBuilder.setTcpNoDelay(isTcpNoDelay);
155 }
156
157 poolingConnectionManager.setDefaultSocketConfig(socketConfigBuilder.build());
158
159 ConnectionConfig.Builder connectionConfigBuilder = ConnectionConfig.custom();
160
161 Integer sendBuffer = SO_SNDBUF.getValue();
162 Integer receiveBuffer = SO_RCVBUF.getValue();
163
164
165 if (sendBuffer != null || receiveBuffer != null) {
166 Integer bufferSize = -1;
167 if (sendBuffer != null) {
168 bufferSize = sendBuffer;
169 }
170
171 if (receiveBuffer != null && receiveBuffer > bufferSize) {
172 bufferSize = receiveBuffer;
173 }
174
175 connectionConfigBuilder.setBufferSize(bufferSize);
176 }
177
178 String contentCharset = HTTP_CONTENT_CHARSET.getValue();
179 if (contentCharset != null) {
180 connectionConfigBuilder.setCharset(Charset.forName(contentCharset));
181 }
182
183 poolingConnectionManager.setDefaultConnectionConfig(connectionConfigBuilder.build());
184
185 return poolingConnectionManager;
186 }
187
188
189
190
191
192
193 protected HttpRequestRetryHandler buildRetryHandler() {
194
195 if (ConfigContext.getCurrentContextConfig().getBooleanProperty(RETRY_SOCKET_EXCEPTION_PROPERTY, false)) {
196 return new DefaultHttpRequestRetryHandler(1, true);
197 }
198
199 return null;
200 }
201
202
203
204
205
206
207 protected RequestConfig buildRequestConfig() {
208 RequestConfig.Builder requestConfigBuilder = RequestConfig.custom();
209
210
211 requestConfigBuilder.setCookieSpec(COOKIE_POLICY.getValueOrDefault(CookieSpecs.STANDARD));
212
213 Integer connectionRequestTimeout = CONNECTION_MANAGER_TIMEOUT.getValue();
214 if (connectionRequestTimeout != null) {
215 requestConfigBuilder.setConnectionRequestTimeout(connectionRequestTimeout);
216 }
217
218 Integer connectionTimeout = CONNECTION_TIMEOUT.getValue();
219 if (connectionTimeout != null) {
220 requestConfigBuilder.setConnectTimeout(connectionTimeout);
221 }
222
223 Boolean isStaleConnectionCheckEnabled = STALE_CONNECTION_CHECK.getValue();
224 if (isStaleConnectionCheckEnabled != null) {
225 requestConfigBuilder.setStaleConnectionCheckEnabled(isStaleConnectionCheckEnabled);
226 }
227
228 requestConfigBuilder.setSocketTimeout(SO_TIMEOUT.getValueOrDefault(DEFAULT_SOCKET_TIMEOUT));
229
230 Boolean isUseExpectContinue = USE_EXPECT_CONTINUE.getValue();
231 if (isUseExpectContinue != null) {
232 requestConfigBuilder.setExpectContinueEnabled(isUseExpectContinue);
233 }
234
235 Integer maxRedirects = MAX_REDIRECTS.getValue();
236 if (maxRedirects != null) {
237 requestConfigBuilder.setMaxRedirects(maxRedirects);
238 }
239
240 Boolean isCircularRedirectsAllowed = ALLOW_CIRCULAR_REDIRECTS.getValue();
241 if (isCircularRedirectsAllowed != null) {
242 requestConfigBuilder.setCircularRedirectsAllowed(isCircularRedirectsAllowed);
243 }
244
245 Boolean isRejectRelativeRedirects = REJECT_RELATIVE_REDIRECT.getValue();
246 if (isRejectRelativeRedirects != null) {
247
248 requestConfigBuilder.setRelativeRedirectsAllowed(!isRejectRelativeRedirects);
249 }
250
251 return requestConfigBuilder.build();
252 }
253
254
255
256
257
258
259
260
261
262
263 protected SSLConnectionSocketFactory buildSslConnectionSocketFactory() {
264 SSLContextBuilder builder = new SSLContextBuilder();
265
266 if (ConfigContext.getCurrentContextConfig().getBooleanProperty(KSBConstants.Config.KSB_ALLOW_SELF_SIGNED_SSL)) {
267 try {
268
269 builder.loadTrustMaterial(null, new TrustSelfSignedStrategy());
270 } catch (NoSuchAlgorithmException e) {
271 throw new RiceRuntimeException(e);
272 } catch (KeyStoreException e) {
273 throw new RiceRuntimeException(e);
274 }
275 }
276
277 SSLConnectionSocketFactory sslsf = null;
278
279 try {
280 if (ConfigContext.getCurrentContextConfig().getBooleanProperty(KSBConstants.Config.KSB_ALLOW_SELF_SIGNED_SSL)) {
281
282 sslsf = new SSLConnectionSocketFactory(builder.build(), new AllowAllHostnameVerifier());
283 } else {
284 sslsf = new SSLConnectionSocketFactory(builder.build());
285 }
286 } catch (NoSuchAlgorithmException e) {
287 throw new RiceRuntimeException(e);
288 } catch (KeyManagementException e) {
289 throw new RiceRuntimeException(e);
290 }
291
292 return sslsf;
293 }
294
295
296
297
298
299
300 @Override
301 public void afterPropertiesSet() throws Exception {
302 customizeHttpClient(HttpClientBuilder.create());
303
304
305 Map<String, String> httpParams = ConfigContext.getCurrentContextConfig().getPropertiesWithPrefix("http.", false);
306
307 for (Map.Entry<String, String> paramEntry : httpParams.entrySet()) {
308 if (!isParamNameSupported(paramEntry.getKey()) && !unsupportedParamsWhitelist.contains(paramEntry)) {
309 LOG.warn("Ignoring unsupported config param \"" + paramEntry.getKey() + "\" with value \"" + paramEntry.getValue() + "\"");
310 }
311 }
312 }
313
314
315
316
317
318
319
320 private boolean isParamNameSupported(String paramName) {
321 for (HttpClientParams param : HttpClientParams.values()) {
322 if (param.getParamName().equals(paramName)) {
323 return true;
324 }
325 }
326
327 return false;
328 }
329 }