I'm migrating Apache httpclient from 4.5 to 5.3 and my app currently chooses from a set of local IPs dynamically.
Example code:
HttpGet request = new HttpGet(url);
request.setRequestConfig(RequestConfig.custom()
.setLocalAddress(someLocalInetAddress)
.build());
In httpclient 5.x the setLocalAddress() has been removed and I need a new way to assign the local address.
I know I can create ConnectionSocketFactory on the ConnectionManager level but this doesn't work for me because it would require explicit configuration for when to use each IP (as far as I understand). I have some other logic which determines the IP and I simply need to set it for the request.
UPDATE:
A "hack" I've found is to create a custom HttpContext and pass it like this
//create a new HttpRoute route and set its local address
final HttpContext context = HttpClientContext.create();
context.setAttribute(HTTP_ROUTE, httpRoute);
client.execute(request, context, handler);
The issue with this is that it overrides the whole httpRoute, not just the localAddress.
There is no such thing as a local address per request. It makes no sense. The local address can only be defined at the HTTP route level.
Subclass DefaultRoutePlanner
and override its #determineLocalAddress
method in order to provide a custom strategy for a local address resolution on a per HTTP route basis.
try (CloseableHttpClient httpclient = HttpClients.custom()
.setRoutePlanner(new DefaultRoutePlanner(DefaultSchemePortResolver.INSTANCE) {
@Override
protected InetAddress determineLocalAddress(final HttpHost firstHop, final HttpContext context) throws HttpException {
return (InetAddress) context.getAttribute("local-address");
}
})
.build()) {
final ClassicHttpRequest request = ClassicRequestBuilder.get()
.setHttpHost(new HttpHost("https", "httpbin.org"))
.setPath("/headers")
.build();
final HttpClientContext clientContext = HttpClientContext.create();
clientContext.setAttribute("local-address", InetAddress.getByAddress(new byte[] { 127, 0, 0, 1}));
System.out.println("Executing request " + request);
httpclient.execute(request, clientContext, response -> {
System.out.println("----------------------------------------");
System.out.println(request + "->" + new StatusLine(response));
EntityUtils.consume(response.getEntity());
return null;
});
}