Apache HttpClient5 - How to set LocalAddress per-request?

62 Views Asked by At

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.

1

There are 1 best solutions below

3
ok2c On BEST ANSWER

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;
    });
}