|
25 | 25 |
|
26 | 26 | import java.io.ByteArrayInputStream; |
27 | 27 | import java.io.IOException; |
| 28 | +import java.net.InetAddress; |
28 | 29 | import java.security.KeyManagementException; |
29 | 30 | import java.security.NoSuchAlgorithmException; |
30 | 31 | import java.security.cert.CertificateException; |
|
48 | 49 | import org.apache.hc.client5.http.impl.classic.HttpClients; |
49 | 50 | import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager; |
50 | 51 | import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder; |
| 52 | +import org.apache.hc.client5.http.impl.routing.DefaultRoutePlanner; |
51 | 53 | import org.apache.hc.client5.http.io.HttpClientConnectionManager; |
52 | 54 | import org.apache.hc.client5.http.protocol.HttpClientContext; |
53 | 55 | import org.apache.hc.client5.http.routing.HttpRoutePlanner; |
|
57 | 59 | import org.apache.hc.core5.http.ClassicHttpResponse; |
58 | 60 | import org.apache.hc.core5.http.Header; |
59 | 61 | import org.apache.hc.core5.http.HttpEntity; |
| 62 | +import org.apache.hc.core5.http.HttpException; |
| 63 | +import org.apache.hc.core5.http.HttpHost; |
60 | 64 | import org.apache.hc.core5.http.HttpResponse; |
61 | 65 | import org.apache.hc.core5.http.config.Registry; |
62 | 66 | import org.apache.hc.core5.http.impl.io.HttpRequestExecutor; |
63 | 67 | import org.apache.hc.core5.http.io.SocketConfig; |
| 68 | +import org.apache.hc.core5.http.protocol.HttpContext; |
64 | 69 | import org.apache.hc.core5.io.CloseMode; |
65 | 70 | import org.apache.hc.core5.pool.PoolStats; |
66 | 71 | import org.apache.hc.core5.ssl.SSLInitializationException; |
|
108 | 113 | @SdkPublicApi |
109 | 114 | public final class Apache5HttpClient implements SdkHttpClient { |
110 | 115 |
|
111 | | - public static final String CLIENT_NAME = "Apache5"; |
| 116 | + public static final String CLIENT_NAME = "Apache5Preview"; |
112 | 117 |
|
113 | 118 | private static final Logger log = Logger.loggerFor(Apache5HttpClient.class); |
114 | 119 | private static final HostnameVerifier DEFAULT_HOSTNAME_VERIFIER = new DefaultHostnameVerifier(); |
@@ -206,7 +211,12 @@ private void addProxyConfig(HttpClientBuilder builder, |
206 | 211 | } |
207 | 212 |
|
208 | 213 | if (routePlanner != null) { |
| 214 | + if (configuration.localAddress != null) { |
| 215 | + log.debug(() -> "localAddress configuration was ignored since Route planner was explicitly provided"); |
| 216 | + } |
209 | 217 | builder.setRoutePlanner(routePlanner); |
| 218 | + } else if (configuration.localAddress != null) { |
| 219 | + builder.setRoutePlanner(new LocalAddressRoutePlanner(configuration.localAddress)); |
210 | 220 | } |
211 | 221 |
|
212 | 222 | if (credentialsProvider != null) { |
@@ -404,6 +414,11 @@ public interface Builder extends SdkHttpClient.Builder<Apache5HttpClient.Builder |
404 | 414 | */ |
405 | 415 | Builder proxyConfiguration(ProxyConfiguration proxyConfiguration); |
406 | 416 |
|
| 417 | + /** |
| 418 | + * Configure the local address that the HTTP client should use for communication. |
| 419 | + */ |
| 420 | + Builder localAddress(InetAddress localAddress); |
| 421 | + |
407 | 422 | /** |
408 | 423 | * Configure whether the client should send an HTTP expect-continue handshake before each request. |
409 | 424 | */ |
@@ -495,6 +510,7 @@ private static final class DefaultBuilder implements Builder { |
495 | 510 | private final AttributeMap.Builder standardOptions = AttributeMap.builder(); |
496 | 511 | private Registry<AuthSchemeFactory> authSchemeRegistry; |
497 | 512 | private ProxyConfiguration proxyConfiguration = ProxyConfiguration.builder().build(); |
| 513 | + private InetAddress localAddress; |
498 | 514 | private Boolean expectContinueEnabled; |
499 | 515 | private HttpRoutePlanner httpRoutePlanner; |
500 | 516 | private CredentialsProvider credentialsProvider; |
@@ -560,6 +576,16 @@ public void setProxyConfiguration(ProxyConfiguration proxyConfiguration) { |
560 | 576 | proxyConfiguration(proxyConfiguration); |
561 | 577 | } |
562 | 578 |
|
| 579 | + @Override |
| 580 | + public Builder localAddress(InetAddress localAddress) { |
| 581 | + this.localAddress = localAddress; |
| 582 | + return this; |
| 583 | + } |
| 584 | + |
| 585 | + public void setLocalAddress(InetAddress localAddress) { |
| 586 | + localAddress(localAddress); |
| 587 | + } |
| 588 | + |
563 | 589 | @Override |
564 | 590 | public Builder expectContinueEnabled(Boolean expectContinueEnabled) { |
565 | 591 | this.expectContinueEnabled = expectContinueEnabled; |
@@ -794,4 +820,18 @@ private SocketConfig buildSocketConfig(AttributeMap standardOptions) { |
794 | 820 | } |
795 | 821 |
|
796 | 822 | } |
| 823 | + |
| 824 | + private static class LocalAddressRoutePlanner extends DefaultRoutePlanner { |
| 825 | + private final InetAddress localAddress; |
| 826 | + |
| 827 | + LocalAddressRoutePlanner(InetAddress localAddress) { |
| 828 | + super(DefaultSchemePortResolver.INSTANCE); |
| 829 | + this.localAddress = localAddress; |
| 830 | + } |
| 831 | + |
| 832 | + @Override |
| 833 | + protected InetAddress determineLocalAddress(HttpHost firstHop, HttpContext context) throws HttpException { |
| 834 | + return localAddress; |
| 835 | + } |
| 836 | + } |
797 | 837 | } |
0 commit comments