1
15
16 package software.amazon.awssdk.http.apache;
17
18 import static java.util.stream.Collectors.groupingBy;
19 import static java.util.stream.Collectors.mapping;
20 import static java.util.stream.Collectors.toList;
21 import static software.amazon.awssdk.utils.NumericUtils.saturatedCast;
22
23 import java.io.IOException;
24 import java.net.InetAddress;
25 import java.security.KeyManagementException;
26 import java.security.NoSuchAlgorithmException;
27 import java.security.cert.CertificateException;
28 import java.security.cert.X509Certificate;
29 import java.time.Duration;
30 import java.util.List;
31 import java.util.Map;
32 import java.util.Optional;
33 import java.util.concurrent.TimeUnit;
34 import java.util.stream.Stream;
35 import javax.net.ssl.HostnameVerifier;
36 import javax.net.ssl.KeyManager;
37 import javax.net.ssl.SSLContext;
38 import javax.net.ssl.TrustManager;
39 import javax.net.ssl.X509TrustManager;
40 import org.apache.http.Header;
41 import org.apache.http.HttpResponse;
42 import org.apache.http.client.CredentialsProvider;
43 import org.apache.http.client.methods.HttpRequestBase;
44 import org.apache.http.client.protocol.HttpClientContext;
45 import org.apache.http.config.Registry;
46 import org.apache.http.config.RegistryBuilder;
47 import org.apache.http.config.SocketConfig;
48 import org.apache.http.conn.ConnectionKeepAliveStrategy;
49 import org.apache.http.conn.HttpClientConnectionManager;
50 import org.apache.http.conn.routing.HttpRoutePlanner;
51 import org.apache.http.conn.socket.ConnectionSocketFactory;
52 import org.apache.http.conn.socket.PlainConnectionSocketFactory;
53 import org.apache.http.conn.ssl.NoopHostnameVerifier;
54 import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
55 import org.apache.http.conn.ssl.SSLInitializationException;
56 import org.apache.http.impl.client.HttpClientBuilder;
57 import org.apache.http.impl.client.HttpClients;
58 import org.apache.http.impl.conn.DefaultSchemePortResolver;
59 import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
60 import org.apache.http.protocol.HttpRequestExecutor;
61 import software.amazon.awssdk.annotations.SdkPublicApi;
62 import software.amazon.awssdk.annotations.SdkTestInternalApi;
63 import software.amazon.awssdk.http.AbortableInputStream;
64 import software.amazon.awssdk.http.ExecutableHttpRequest;
65 import software.amazon.awssdk.http.HttpExecuteRequest;
66 import software.amazon.awssdk.http.HttpExecuteResponse;
67 import software.amazon.awssdk.http.SdkHttpClient;
68 import software.amazon.awssdk.http.SdkHttpConfigurationOption;
69 import software.amazon.awssdk.http.SdkHttpResponse;
70 import software.amazon.awssdk.http.SystemPropertyTlsKeyManagersProvider;
71 import software.amazon.awssdk.http.TlsKeyManagersProvider;
72 import software.amazon.awssdk.http.TlsTrustManagersProvider;
73 import software.amazon.awssdk.http.apache.internal.ApacheHttpRequestConfig;
74 import software.amazon.awssdk.http.apache.internal.DefaultConfiguration;
75 import software.amazon.awssdk.http.apache.internal.SdkProxyRoutePlanner;
76 import software.amazon.awssdk.http.apache.internal.conn.ClientConnectionManagerFactory;
77 import software.amazon.awssdk.http.apache.internal.conn.IdleConnectionReaper;
78 import software.amazon.awssdk.http.apache.internal.conn.SdkConnectionKeepAliveStrategy;
79 import software.amazon.awssdk.http.apache.internal.conn.SdkTlsSocketFactory;
80 import software.amazon.awssdk.http.apache.internal.impl.ApacheHttpRequestFactory;
81 import software.amazon.awssdk.http.apache.internal.impl.ApacheSdkHttpClient;
82 import software.amazon.awssdk.http.apache.internal.impl.ConnectionManagerAwareHttpClient;
83 import software.amazon.awssdk.http.apache.internal.utils.ApacheUtils;
84 import software.amazon.awssdk.utils.AttributeMap;
85 import software.amazon.awssdk.utils.Logger;
86 import software.amazon.awssdk.utils.Validate;
87
88
97 @SdkPublicApi
98 public final class ApacheHttpClient implements SdkHttpClient {
99
100 public static final String CLIENT_NAME = "Apache";
101
102 private static final Logger log = Logger.loggerFor(ApacheHttpClient.class);
103
104 private final ApacheHttpRequestFactory apacheHttpRequestFactory = new ApacheHttpRequestFactory();
105 private final ConnectionManagerAwareHttpClient httpClient;
106 private final ApacheHttpRequestConfig requestConfig;
107 private final AttributeMap resolvedOptions;
108
109 @SdkTestInternalApi
110 ApacheHttpClient(ConnectionManagerAwareHttpClient httpClient,
111 ApacheHttpRequestConfig requestConfig,
112 AttributeMap resolvedOptions) {
113 this.httpClient = httpClient;
114 this.requestConfig = requestConfig;
115 this.resolvedOptions = resolvedOptions;
116 }
117
118 private ApacheHttpClient(DefaultBuilder builder, AttributeMap resolvedOptions) {
119 this.httpClient = createClient(builder, resolvedOptions);
120 this.requestConfig = createRequestConfig(builder, resolvedOptions);
121 this.resolvedOptions = resolvedOptions;
122 }
123
124 public static Builder builder() {
125 return new DefaultBuilder();
126 }
127
128 private ConnectionManagerAwareHttpClient createClient(ApacheHttpClient.DefaultBuilder configuration,
129 AttributeMap standardOptions) {
130 ApacheConnectionManagerFactory cmFactory = new ApacheConnectionManagerFactory();
131
132 HttpClientBuilder builder = HttpClients.custom();
133
134
135
136 HttpClientConnectionManager cm = cmFactory.create(configuration, standardOptions);
137
138 builder.setRequestExecutor(new HttpRequestExecutor())
139
140 .disableContentCompression()
141 .setKeepAliveStrategy(buildKeepAliveStrategy(standardOptions))
142 .disableRedirectHandling()
143 .disableAutomaticRetries()
144 .setUserAgent("")
145 .setConnectionManager(ClientConnectionManagerFactory.wrap(cm));
146
147 addProxyConfig(builder, configuration);
148
149 if (useIdleConnectionReaper(standardOptions)) {
150 IdleConnectionReaper.getInstance().registerConnectionManager(
151 cm, standardOptions.get(SdkHttpConfigurationOption.CONNECTION_MAX_IDLE_TIMEOUT).toMillis());
152 }
153
154 return new ApacheSdkHttpClient(builder.build(), cm);
155 }
156
157 private void addProxyConfig(HttpClientBuilder builder,
158 DefaultBuilder configuration) {
159 ProxyConfiguration proxyConfiguration = configuration.proxyConfiguration;
160
161 Validate.isTrue(configuration.httpRoutePlanner == null || !isProxyEnabled(proxyConfiguration),
162 "The httpRoutePlanner and proxyConfiguration can't both be configured.");
163 Validate.isTrue(configuration.credentialsProvider == null || !isAuthenticatedProxy(proxyConfiguration),
164 "The credentialsProvider and proxyConfiguration username/password can't both be configured.");
165
166 HttpRoutePlanner routePlanner = configuration.httpRoutePlanner;
167 if (isProxyEnabled(proxyConfiguration)) {
168 log.debug(() -> "Configuring Proxy. Proxy Host: " + proxyConfiguration.host());
169 routePlanner = new SdkProxyRoutePlanner(proxyConfiguration.host(),
170 proxyConfiguration.port(),
171 proxyConfiguration.scheme(),
172 proxyConfiguration.nonProxyHosts());
173 }
174
175 CredentialsProvider credentialsProvider = configuration.credentialsProvider;
176 if (isAuthenticatedProxy(proxyConfiguration)) {
177 credentialsProvider = ApacheUtils.newProxyCredentialsProvider(proxyConfiguration);
178 }
179
180 if (routePlanner != null) {
181 builder.setRoutePlanner(routePlanner);
182 }
183
184 if (credentialsProvider != null) {
185 builder.setDefaultCredentialsProvider(credentialsProvider);
186 }
187 }
188
189 private ConnectionKeepAliveStrategy buildKeepAliveStrategy(AttributeMap standardOptions) {
190 long maxIdle = standardOptions.get(SdkHttpConfigurationOption.CONNECTION_MAX_IDLE_TIMEOUT).toMillis();
191 return maxIdle > 0 ? new SdkConnectionKeepAliveStrategy(maxIdle) : null;
192 }
193
194 private boolean useIdleConnectionReaper(AttributeMap standardOptions) {
195 return Boolean.TRUE.equals(standardOptions.get(SdkHttpConfigurationOption.REAP_IDLE_CONNECTIONS));
196 }
197
198 private boolean isAuthenticatedProxy(ProxyConfiguration proxyConfiguration) {
199 return proxyConfiguration.username() != null && proxyConfiguration.password() != null;
200 }
201
202 private boolean isProxyEnabled(ProxyConfiguration proxyConfiguration) {
203 return proxyConfiguration.host() != null
204 && proxyConfiguration.port() > 0;
205 }
206
207 @Override
208 public ExecutableHttpRequest prepareRequest(HttpExecuteRequest request) {
209 HttpRequestBase apacheRequest = toApacheRequest(request);
210 return new ExecutableHttpRequest() {
211 @Override
212 public HttpExecuteResponse call() throws IOException {
213 return execute(apacheRequest);
214 }
215
216 @Override
217 public void abort() {
218 apacheRequest.abort();
219 }
220 };
221 }
222
223 @Override
224 public void close() {
225 HttpClientConnectionManager cm = httpClient.getHttpClientConnectionManager();
226 IdleConnectionReaper.getInstance().deregisterConnectionManager(cm);
227 cm.shutdown();
228 }
229
230 private HttpExecuteResponse execute(HttpRequestBase apacheRequest) throws IOException {
231 HttpClientContext localRequestContext = ApacheUtils.newClientContext(requestConfig.proxyConfiguration());
232 HttpResponse httpResponse = httpClient.execute(apacheRequest, localRequestContext);
233 return createResponse(httpResponse, apacheRequest);
234 }
235
236 private HttpRequestBase toApacheRequest(HttpExecuteRequest request) {
237 return apacheHttpRequestFactory.create(request, requestConfig);
238 }
239
240
248 private HttpExecuteResponse createResponse(org.apache.http.HttpResponse apacheHttpResponse,
249 HttpRequestBase apacheRequest) throws IOException {
250 SdkHttpResponse response = SdkHttpResponse.builder()
251 .statusCode(apacheHttpResponse.getStatusLine().getStatusCode())
252 .statusText(apacheHttpResponse.getStatusLine().getReasonPhrase())
253 .headers(transformHeaders(apacheHttpResponse))
254 .build();
255 AbortableInputStream responseBody = apacheHttpResponse.getEntity() != null ?
256 toAbortableInputStream(apacheHttpResponse, apacheRequest) : null;
257
258 return HttpExecuteResponse.builder().response(response).responseBody(responseBody).build();
259
260 }
261
262 private AbortableInputStream toAbortableInputStream(HttpResponse apacheHttpResponse, HttpRequestBase apacheRequest)
263 throws IOException {
264 return AbortableInputStream.create(apacheHttpResponse.getEntity().getContent(), apacheRequest::abort);
265 }
266
267 private Map<String, List<String>> transformHeaders(HttpResponse apacheHttpResponse) {
268 return Stream.of(apacheHttpResponse.getAllHeaders())
269 .collect(groupingBy(Header::getName, mapping(Header::getValue, toList())));
270 }
271
272 private ApacheHttpRequestConfig createRequestConfig(DefaultBuilder builder,
273 AttributeMap resolvedOptions) {
274 return ApacheHttpRequestConfig.builder()
275 .socketTimeout(resolvedOptions.get(SdkHttpConfigurationOption.READ_TIMEOUT))
276 .connectionTimeout(resolvedOptions.get(SdkHttpConfigurationOption.CONNECTION_TIMEOUT))
277 .connectionAcquireTimeout(
278 resolvedOptions.get(SdkHttpConfigurationOption.CONNECTION_ACQUIRE_TIMEOUT))
279 .proxyConfiguration(builder.proxyConfiguration)
280 .localAddress(Optional.ofNullable(builder.localAddress).orElse(null))
281 .expectContinueEnabled(Optional.ofNullable(builder.expectContinueEnabled)
282 .orElse(DefaultConfiguration.EXPECT_CONTINUE_ENABLED))
283 .build();
284 }
285
286 @Override
287 public String clientName() {
288 return CLIENT_NAME;
289 }
290
291
303 public interface Builder extends SdkHttpClient.Builder<ApacheHttpClient.Builder> {
304
305
309 Builder socketTimeout(Duration socketTimeout);
310
311
315 Builder connectionTimeout(Duration connectionTimeout);
316
317
322 Builder connectionAcquisitionTimeout(Duration connectionAcquisitionTimeout);
323
324
328 Builder maxConnections(Integer maxConnections);
329
330
333 Builder proxyConfiguration(ProxyConfiguration proxyConfiguration);
334
335
338 Builder localAddress(InetAddress localAddress);
339
340
343 Builder expectContinueEnabled(Boolean expectContinueEnabled);
344
345
348 Builder connectionTimeToLive(Duration connectionTimeToLive);
349
350
353 Builder connectionMaxIdleTime(Duration maxIdleConnectionTimeout);
354
355
361 Builder useIdleConnectionReaper(Boolean useConnectionReaper);
362
363
367 Builder httpRoutePlanner(HttpRoutePlanner proxyConfiguration);
368
369
373 Builder credentialsProvider(CredentialsProvider credentialsProvider);
374
375
383 Builder tlsKeyManagersProvider(TlsKeyManagersProvider tlsKeyManagersProvider);
384
385
389 Builder tlsTrustManagersProvider(TlsTrustManagersProvider tlsTrustManagersProvider);
390 }
391
392 private static final class DefaultBuilder implements Builder {
393 private final AttributeMap.Builder standardOptions = AttributeMap.builder();
394 private ProxyConfiguration proxyConfiguration = ProxyConfiguration.builder().build();
395 private InetAddress localAddress;
396 private Boolean expectContinueEnabled;
397 private HttpRoutePlanner httpRoutePlanner;
398 private CredentialsProvider credentialsProvider;
399
400 private DefaultBuilder() {
401 }
402
403 @Override
404 public Builder socketTimeout(Duration socketTimeout) {
405 standardOptions.put(SdkHttpConfigurationOption.READ_TIMEOUT, socketTimeout);
406 return this;
407 }
408
409 public void setSocketTimeout(Duration socketTimeout) {
410 socketTimeout(socketTimeout);
411 }
412
413 @Override
414 public Builder connectionTimeout(Duration connectionTimeout) {
415 standardOptions.put(SdkHttpConfigurationOption.CONNECTION_TIMEOUT, connectionTimeout);
416 return this;
417 }
418
419 public void setConnectionTimeout(Duration connectionTimeout) {
420 connectionTimeout(connectionTimeout);
421 }
422
423
428 @Override
429 public Builder connectionAcquisitionTimeout(Duration connectionAcquisitionTimeout) {
430 Validate.isPositive(connectionAcquisitionTimeout, "connectionAcquisitionTimeout");
431 standardOptions.put(SdkHttpConfigurationOption.CONNECTION_ACQUIRE_TIMEOUT, connectionAcquisitionTimeout);
432 return this;
433 }
434
435 public void setConnectionAcquisitionTimeout(Duration connectionAcquisitionTimeout) {
436 connectionAcquisitionTimeout(connectionAcquisitionTimeout);
437 }
438
439 @Override
440 public Builder maxConnections(Integer maxConnections) {
441 standardOptions.put(SdkHttpConfigurationOption.MAX_CONNECTIONS, maxConnections);
442 return this;
443 }
444
445 public void setMaxConnections(Integer maxConnections) {
446 maxConnections(maxConnections);
447 }
448
449 @Override
450 public Builder proxyConfiguration(ProxyConfiguration proxyConfiguration) {
451 this.proxyConfiguration = proxyConfiguration;
452 return this;
453 }
454
455 public void setProxyConfiguration(ProxyConfiguration proxyConfiguration) {
456 proxyConfiguration(proxyConfiguration);
457 }
458
459 @Override
460 public Builder localAddress(InetAddress localAddress) {
461 this.localAddress = localAddress;
462 return this;
463 }
464
465 public void setLocalAddress(InetAddress localAddress) {
466 localAddress(localAddress);
467 }
468
469 @Override
470 public Builder expectContinueEnabled(Boolean expectContinueEnabled) {
471 this.expectContinueEnabled = expectContinueEnabled;
472 return this;
473 }
474
475 public void setExpectContinueEnabled(Boolean useExpectContinue) {
476 this.expectContinueEnabled = useExpectContinue;
477 }
478
479 @Override
480 public Builder connectionTimeToLive(Duration connectionTimeToLive) {
481 standardOptions.put(SdkHttpConfigurationOption.CONNECTION_TIME_TO_LIVE, connectionTimeToLive);
482 return this;
483 }
484
485 public void setConnectionTimeToLive(Duration connectionTimeToLive) {
486 connectionTimeToLive(connectionTimeToLive);
487 }
488
489 @Override
490 public Builder connectionMaxIdleTime(Duration maxIdleConnectionTimeout) {
491 standardOptions.put(SdkHttpConfigurationOption.CONNECTION_MAX_IDLE_TIMEOUT, maxIdleConnectionTimeout);
492 return this;
493 }
494
495 public void setConnectionMaxIdleTime(Duration connectionMaxIdleTime) {
496 connectionMaxIdleTime(connectionMaxIdleTime);
497 }
498
499 @Override
500 public Builder useIdleConnectionReaper(Boolean useIdleConnectionReaper) {
501 standardOptions.put(SdkHttpConfigurationOption.REAP_IDLE_CONNECTIONS, useIdleConnectionReaper);
502 return this;
503 }
504
505 public void setUseIdleConnectionReaper(Boolean useIdleConnectionReaper) {
506 useIdleConnectionReaper(useIdleConnectionReaper);
507 }
508
509 @Override
510 public Builder httpRoutePlanner(HttpRoutePlanner httpRoutePlanner) {
511 this.httpRoutePlanner = httpRoutePlanner;
512 return this;
513 }
514
515 public void setHttpRoutePlanner(HttpRoutePlanner httpRoutePlanner) {
516 httpRoutePlanner(httpRoutePlanner);
517 }
518
519 @Override
520 public Builder credentialsProvider(CredentialsProvider credentialsProvider) {
521 this.credentialsProvider = credentialsProvider;
522 return this;
523 }
524
525 public void setCredentialsProvider(CredentialsProvider credentialsProvider) {
526 credentialsProvider(credentialsProvider);
527 }
528
529 @Override
530 public Builder tlsKeyManagersProvider(TlsKeyManagersProvider tlsKeyManagersProvider) {
531 standardOptions.put(SdkHttpConfigurationOption.TLS_KEY_MANAGERS_PROVIDER, tlsKeyManagersProvider);
532 return this;
533 }
534
535 public void setTlsKeyManagersProvider(TlsKeyManagersProvider tlsKeyManagersProvider) {
536 tlsKeyManagersProvider(tlsKeyManagersProvider);
537 }
538
539 @Override
540 public Builder tlsTrustManagersProvider(TlsTrustManagersProvider tlsTrustManagersProvider) {
541 standardOptions.put(SdkHttpConfigurationOption.TLS_TRUST_MANAGERS_PROVIDER, tlsTrustManagersProvider);
542 return this;
543 }
544
545 public void setTlsTrustManagersProvider(TlsTrustManagersProvider tlsTrustManagersProvider) {
546 tlsTrustManagersProvider(tlsTrustManagersProvider);
547 }
548
549 @Override
550 public SdkHttpClient buildWithDefaults(AttributeMap serviceDefaults) {
551 AttributeMap resolvedOptions = standardOptions.build().merge(serviceDefaults).merge(
552 SdkHttpConfigurationOption.GLOBAL_HTTP_DEFAULTS);
553 return new ApacheHttpClient(this, resolvedOptions);
554 }
555 }
556
557 private static class ApacheConnectionManagerFactory {
558
559 public HttpClientConnectionManager create(ApacheHttpClient.DefaultBuilder configuration,
560 AttributeMap standardOptions) {
561 ConnectionSocketFactory sslsf = getPreferredSocketFactory(configuration, standardOptions);
562
563 PoolingHttpClientConnectionManager cm = new
564 PoolingHttpClientConnectionManager(
565 createSocketFactoryRegistry(sslsf),
566 null,
567 DefaultSchemePortResolver.INSTANCE,
568 null,
569 standardOptions.get(SdkHttpConfigurationOption.CONNECTION_TIME_TO_LIVE).toMillis(),
570 TimeUnit.MILLISECONDS);
571
572 cm.setDefaultMaxPerRoute(standardOptions.get(SdkHttpConfigurationOption.MAX_CONNECTIONS));
573 cm.setMaxTotal(standardOptions.get(SdkHttpConfigurationOption.MAX_CONNECTIONS));
574 cm.setDefaultSocketConfig(buildSocketConfig(standardOptions));
575
576 return cm;
577 }
578
579 private ConnectionSocketFactory getPreferredSocketFactory(ApacheHttpClient.DefaultBuilder configuration,
580 AttributeMap standardOptions) {
581
582 return new SdkTlsSocketFactory(getSslContext(standardOptions),
583 getHostNameVerifier(standardOptions));
584 }
585
586 private HostnameVerifier getHostNameVerifier(AttributeMap standardOptions) {
587 return standardOptions.get(SdkHttpConfigurationOption.TRUST_ALL_CERTIFICATES)
588 ? NoopHostnameVerifier.INSTANCE
589 : SSLConnectionSocketFactory.getDefaultHostnameVerifier();
590 }
591
592 private SSLContext getSslContext(AttributeMap standardOptions) {
593 Validate.isTrue(standardOptions.get(SdkHttpConfigurationOption.TLS_TRUST_MANAGERS_PROVIDER) == null ||
594 !standardOptions.get(SdkHttpConfigurationOption.TRUST_ALL_CERTIFICATES),
595 "A TlsTrustManagerProvider can't be provided if TrustAllCertificates is also set");
596
597 TrustManager[] trustManagers = null;
598 if (standardOptions.get(SdkHttpConfigurationOption.TLS_TRUST_MANAGERS_PROVIDER) != null) {
599 trustManagers = standardOptions.get(SdkHttpConfigurationOption.TLS_TRUST_MANAGERS_PROVIDER).trustManagers();
600 }
601
602 if (standardOptions.get(SdkHttpConfigurationOption.TRUST_ALL_CERTIFICATES)) {
603 log.warn(() -> "SSL Certificate verification is disabled. This is not a safe setting and should only be "
604 + "used for testing.");
605 trustManagers = trustAllTrustManager();
606 }
607
608 TlsKeyManagersProvider provider = standardOptions.get(SdkHttpConfigurationOption.TLS_KEY_MANAGERS_PROVIDER);
609 KeyManager[] keyManagers = provider.keyManagers();
610
611 try {
612 SSLContext sslcontext = SSLContext.getInstance("TLS");
613
614 sslcontext.init(keyManagers, trustManagers, null);
615 return sslcontext;
616 } catch (final NoSuchAlgorithmException | KeyManagementException ex) {
617 throw new SSLInitializationException(ex.getMessage(), ex);
618 }
619 }
620
621
624 private static TrustManager[] trustAllTrustManager() {
625 return new TrustManager[] {
626 new X509TrustManager() {
627 @Override
628 public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
629 log.debug(() -> "Accepting a client certificate: " + x509Certificates[0].getSubjectDN());
630 }
631
632 @Override
633 public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
634 log.debug(() -> "Accepting a client certificate: " + x509Certificates[0].getSubjectDN());
635 }
636
637 @Override
638 public X509Certificate[] getAcceptedIssuers() {
639 return new X509Certificate[0];
640 }
641 }
642 };
643 }
644
645 private SocketConfig buildSocketConfig(AttributeMap standardOptions) {
646 return SocketConfig.custom()
647
648 .setSoKeepAlive(false)
649 .setSoTimeout(
650 saturatedCast(standardOptions.get(SdkHttpConfigurationOption.READ_TIMEOUT)
651 .toMillis()))
652 .setTcpNoDelay(true)
653 .build();
654 }
655
656 private Registry<ConnectionSocketFactory> createSocketFactoryRegistry(ConnectionSocketFactory sslSocketFactory) {
657 return RegistryBuilder.<ConnectionSocketFactory>create()
658 .register("http", PlainConnectionSocketFactory.getSocketFactory())
659 .register("https", sslSocketFactory)
660 .build();
661 }
662 }
663 }
664