Skip to content

Commit 1d28a72

Browse files
author
Stephen Powis
committed
Update HttpClientRestClient
1 parent ce51fc4 commit 1d28a72

File tree

3 files changed

+84
-55
lines changed

3 files changed

+84
-55
lines changed

src/main/java/org/sourcelab/kafka/connect/apiclient/Configuration.java

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ public final class Configuration {
2929
// Defines the URL/Hostname of Kafka-Connect
3030
private final String apiHost;
3131

32+
// Optional Connection settings
33+
private int requestTimeoutInSeconds = 300;
34+
3235
// Optional SSL options
3336
private boolean ignoreInvalidSslCertificates = false;
3437
private File trustStoreFile = null;
@@ -115,6 +118,16 @@ public Configuration useTrustStore(final File trustStorePath, final String passw
115118
return this;
116119
}
117120

121+
/**
122+
* Set the request timeout value, in seconds.
123+
* @param requestTimeoutInSeconds How long before a request times out, in seconds.
124+
* @return Configuration instance.
125+
*/
126+
public Configuration useRequestTimeoutInSeconds(final int requestTimeoutInSeconds) {
127+
this.requestTimeoutInSeconds = requestTimeoutInSeconds;
128+
return this;
129+
}
130+
118131
public String getProxyHost() {
119132
return proxyHost;
120133
}
@@ -151,10 +164,15 @@ public String getTrustStorePassword() {
151164
return trustStorePassword;
152165
}
153166

167+
public int getRequestTimeoutInSeconds() {
168+
return requestTimeoutInSeconds;
169+
}
170+
154171
@Override
155172
public String toString() {
156173
final StringBuilder stringBuilder = new StringBuilder("Configuration{")
157-
.append("apiHost='").append(apiHost).append('\'');
174+
.append("apiHost='").append(apiHost).append('\'')
175+
.append(", requestTimeout='").append(requestTimeoutInSeconds).append('\'');
158176
if (proxyHost != null) {
159177
stringBuilder
160178
.append(", proxy='").append(proxyScheme).append("://");
@@ -166,6 +184,13 @@ public String toString() {
166184

167185
stringBuilder.append(proxyHost).append(":").append(proxyPort).append('\'');
168186
}
187+
stringBuilder.append(", ignoreInvalidSslCertificates='").append(ignoreInvalidSslCertificates).append('\'');
188+
if (trustStoreFile != null) {
189+
stringBuilder.append(", sslTrustStoreFile='").append(trustStoreFile).append('\'');
190+
if (trustStorePassword != null) {
191+
stringBuilder.append(", sslTrustStorePassword='******'");
192+
}
193+
}
169194
stringBuilder.append('}');
170195

171196
return stringBuilder.toString();

src/main/java/org/sourcelab/kafka/connect/apiclient/rest/HttpClientRestClient.java

Lines changed: 31 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
package org.sourcelab.kafka.connect.apiclient.rest;
1919

20+
import org.apache.http.Header;
2021
import org.apache.http.HttpHost;
2122
import org.apache.http.NameValuePair;
2223
import org.apache.http.auth.AuthScope;
@@ -30,8 +31,6 @@
3031
import org.apache.http.client.methods.HttpPost;
3132
import org.apache.http.client.methods.HttpPut;
3233
import org.apache.http.client.utils.URIBuilder;
33-
import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
34-
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
3534
import org.apache.http.entity.StringEntity;
3635
import org.apache.http.impl.client.BasicCredentialsProvider;
3736
import org.apache.http.impl.client.CloseableHttpClient;
@@ -51,6 +50,8 @@
5150
import java.net.URISyntaxException;
5251
import java.nio.charset.StandardCharsets;
5352
import java.util.ArrayList;
53+
import java.util.Arrays;
54+
import java.util.Collection;
5455
import java.util.Collections;
5556
import java.util.List;
5657
import java.util.Map;
@@ -62,6 +63,15 @@
6263
public class HttpClientRestClient implements RestClient {
6364
private static final Logger logger = LoggerFactory.getLogger(HttpClientRestClient.class);
6465

66+
/**
67+
* Default headers included with every request.
68+
*/
69+
private static final Collection<Header> DEFAULT_HEADERS = Collections.unmodifiableCollection(Arrays.asList(
70+
new BasicHeader("Accept", "application/json"),
71+
new BasicHeader("Content-Type", "application/json")
72+
));
73+
74+
6575
/**
6676
* Save a copy of the configuration.
6777
*/
@@ -72,7 +82,6 @@ public class HttpClientRestClient implements RestClient {
7282
*/
7383
private CloseableHttpClient httpClient;
7484

75-
7685
/**
7786
* Constructor.
7887
*/
@@ -92,20 +101,14 @@ public void init(final Configuration configuration) {
92101
// Create https context builder utility.
93102
final HttpsContextBuilder httpsContextBuilder = new HttpsContextBuilder(configuration);
94103

95-
// Allow TLSv1.2, TLSv1.1, TLSv1 protocols
96-
final LayeredConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(
97-
httpsContextBuilder.getSslContext(),
98-
new String[] { "TLSv1.2", "TLSv1.1", "TLSv1" },
99-
null,
100-
httpsContextBuilder.getHostnameVerifier()
101-
);
102-
103104
// Setup client builder
104105
final HttpClientBuilder clientBuilder = HttpClientBuilder.create();
105106
clientBuilder
106-
// 3 min timeout?
107-
.setConnectionTimeToLive(300, TimeUnit.SECONDS)
108-
.setSSLSocketFactory(sslSocketFactory);
107+
// Define timeout
108+
.setConnectionTimeToLive(configuration.getRequestTimeoutInSeconds(), TimeUnit.SECONDS)
109+
110+
// Define SSL Socket Factory instance.
111+
.setSSLSocketFactory(httpsContextBuilder.createSslSocketFactory());
109112

110113
// Define our RequestConfigBuilder
111114
final RequestConfig.Builder requestConfigBuilder = RequestConfig.custom();
@@ -192,7 +195,7 @@ public RestResponse submitRequest(final Request request) throws RestException {
192195
* @param <T> The type that ResponseHandler returns.
193196
* @return Parsed response.
194197
*/
195-
private <T> T submitGetRequest(final String url, final Map<String, String> getParams, final ResponseHandler<T> responseHandler) throws IOException {
198+
private <T> T submitGetRequest(final String url, final Map<String, String> getParams, final ResponseHandler<T> responseHandler) {
196199
try {
197200
// Construct URI including our request parameters.
198201
final URIBuilder uriBuilder = new URIBuilder(url)
@@ -206,11 +209,8 @@ private <T> T submitGetRequest(final String url, final Map<String, String> getPa
206209
// Build Get Request
207210
final HttpGet get = new HttpGet(uriBuilder.build());
208211

209-
// Add Accept header.
210-
get.addHeader(new BasicHeader("Accept", "application/json"));
211-
212-
// Conditionally add content-type header?
213-
get.addHeader(new BasicHeader("Content-Type", "application/json"));
212+
// Add default headers.
213+
DEFAULT_HEADERS.forEach(get::addHeader);
214214

215215
logger.debug("Executing request {}", get.getRequestLine());
216216

@@ -233,18 +233,12 @@ private <T> T submitGetRequest(final String url, final Map<String, String> getPa
233233
* @param <T> The type that ResponseHandler returns.
234234
* @return Parsed response.
235235
*/
236-
private <T> T submitPostRequest(final String url, final Object requestBody, final ResponseHandler<T> responseHandler) throws IOException {
236+
private <T> T submitPostRequest(final String url, final Object requestBody, final ResponseHandler<T> responseHandler) {
237237
try {
238238
final HttpPost post = new HttpPost(url);
239239

240-
// Add Accept header.
241-
post.addHeader(new BasicHeader("Accept", "application/json"));
242-
243-
// Conditionally add content-type header?
244-
post.addHeader(new BasicHeader("Content-Type", "application/json"));
245-
246-
// Define required auth params
247-
final List<NameValuePair> params = new ArrayList<>();
240+
// Add default headers.
241+
DEFAULT_HEADERS.forEach(post::addHeader);
248242

249243
// Convert to Json
250244
final String jsonPayloadStr = JacksonFactory.newInstance().writeValueAsString(requestBody);
@@ -272,19 +266,12 @@ private <T> T submitPostRequest(final String url, final Object requestBody, fina
272266
* @param <T> The type that ResponseHandler returns.
273267
* @return Parsed response.
274268
*/
275-
private <T> T submitPutRequest(final String url, final Object requestBody, final ResponseHandler<T> responseHandler) throws IOException {
269+
private <T> T submitPutRequest(final String url, final Object requestBody, final ResponseHandler<T> responseHandler) {
276270
try {
277-
// Construct URI including our request parameters.
278-
final URIBuilder uriBuilder = new URIBuilder(url)
279-
.setCharset(StandardCharsets.UTF_8);
280-
281271
final HttpPut put = new HttpPut(url);
282272

283-
// Add Accept header.
284-
put.addHeader(new BasicHeader("Accept", "application/json"));
285-
286-
// Conditionally add content-type header?
287-
put.addHeader(new BasicHeader("Content-Type", "application/json"));
273+
// Add default headers.
274+
DEFAULT_HEADERS.forEach(put::addHeader);
288275

289276
// Convert to Json and submit as payload.
290277
final String jsonPayloadStr = JacksonFactory.newInstance().writeValueAsString(requestBody);
@@ -294,7 +281,7 @@ private <T> T submitPutRequest(final String url, final Object requestBody, final
294281

295282
// Execute and return
296283
return httpClient.execute(put, responseHandler);
297-
} catch (final ClientProtocolException | SocketException | URISyntaxException connectionException) {
284+
} catch (final ClientProtocolException | SocketException connectionException) {
298285
// Typically this is a connection issue.
299286
throw new ConnectionException(connectionException.getMessage(), connectionException);
300287
} catch (final IOException ioException) {
@@ -311,22 +298,12 @@ private <T> T submitPutRequest(final String url, final Object requestBody, final
311298
* @param <T> The type that ResponseHandler returns.
312299
* @return Parsed response.
313300
*/
314-
private <T> T submitDeleteRequest(final String url, final Object requestBody, final ResponseHandler<T> responseHandler) throws IOException {
301+
private <T> T submitDeleteRequest(final String url, final Object requestBody, final ResponseHandler<T> responseHandler) {
315302
try {
316-
// Construct URI including our request parameters.
317-
final URIBuilder uriBuilder = new URIBuilder(url)
318-
.setCharset(StandardCharsets.UTF_8);
319-
320303
final HttpDelete delete = new HttpDelete(url);
321304

322-
// Add Accept header.
323-
delete.addHeader(new BasicHeader("Accept", "application/json"));
324-
325-
// Conditionally add content-type header?
326-
delete.addHeader(new BasicHeader("Content-Type", "application/json"));
327-
328-
// Define required auth params
329-
final List<NameValuePair> params = new ArrayList<>();
305+
// Add default headers.
306+
DEFAULT_HEADERS.forEach(delete::addHeader);
330307

331308
// Convert to Json
332309
final String jsonPayloadStr = JacksonFactory.newInstance().writeValueAsString(requestBody);
@@ -335,7 +312,7 @@ private <T> T submitDeleteRequest(final String url, final Object requestBody, fi
335312

336313
// Execute and return
337314
return httpClient.execute(delete, responseHandler);
338-
} catch (final ClientProtocolException | SocketException | URISyntaxException connectionException) {
315+
} catch (final ClientProtocolException | SocketException connectionException) {
339316
// Typically this is a connection issue.
340317
throw new ConnectionException(connectionException.getMessage(), connectionException);
341318
} catch (final IOException ioException) {

src/main/java/org/sourcelab/kafka/connect/apiclient/rest/HttpsContextBuilder.java

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
package org.sourcelab.kafka.connect.apiclient.rest;
1919

20+
import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
2021
import org.apache.http.conn.ssl.NoopHostnameVerifier;
2122
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
2223
import org.apache.http.ssl.SSLContexts;
@@ -41,6 +42,11 @@
4142
* Utility for properly configuring the SSL Context based on client configuration settings.
4243
*/
4344
class HttpsContextBuilder {
45+
/**
46+
* Accept TLS1.2, 1.1, and 1.0 protocols.
47+
*/
48+
private static final String[] sslProtocols = new String[] { "TLSv1.2", "TLSv1.1", "TLSv1" };
49+
4450
/**
4551
* Client configuration.
4652
*/
@@ -114,4 +120,25 @@ SSLContext getSslContext() {
114120

115121
return sslcontext;
116122
}
123+
124+
/**
125+
* Get allowed SSL Protocols.
126+
* @return allowed SslProtocols.
127+
*/
128+
private String[] getSslProtocols() {
129+
return sslProtocols;
130+
}
131+
132+
/**
133+
* Properly configured SslSocketFactory based on client configuration.
134+
* @return SslSocketFactory instance.
135+
*/
136+
LayeredConnectionSocketFactory createSslSocketFactory() {
137+
return new SSLConnectionSocketFactory(
138+
getSslContext(),
139+
getSslProtocols(),
140+
null,
141+
getHostnameVerifier()
142+
);
143+
}
117144
}

0 commit comments

Comments
 (0)