4

In Apache HttpClient 4.2 one could create a DefaultHttpClient and set a host such that those making an execute call would not have to provide the host information in the input request URI, i.e.:

HttpHost targetHost = new HttpHost(host, port, secure ? "https" : "http");      
DefaultHttpClient defaultHttp = new DefaultHttpClient(connectionManager);
defaultHttp.getParams().setParameter(ClientPNames.DEFAULT_HOST, targetHost);

I do admit this strategy appears very awkward, I inherited this code :). I'm sure there's an even better way to do this in 4.2.

I'm looking to upgrade to 4.3 and noticed that DefaultHttpClient and ClientPNames are now both deprecated in favor of HttpClientBuilder and RequestConfig respectively. However I can find no such way to define a default target with RequestConfig.

Documentation for execute does reference that that input target parameter can accept null, so I'm sure there is still a way to facilitate this, but I'm struggling to figure this out:

target - the target host for the request. Implementations may accept null if they can still determine a route, for example to a default target or by inspecting the request.

ok2c
  • 26,450
  • 5
  • 63
  • 71
weak
  • 207
  • 1
  • 3
  • 6

1 Answers1

5

This should do the trick

HttpRoutePlanner rp = new DefaultRoutePlanner(DefaultSchemePortResolver.INSTANCE) {

    @Override
    public HttpRoute determineRoute(
            final HttpHost host,
            final HttpRequest request,
            final HttpContext context) throws HttpException {
        HttpHost target = host != null ? host : new HttpHost("some.default.host");
        return super.determineRoute(target, request, context);
    }
};

CloseableHttpClient client = HttpClients.custom()
        .setRoutePlanner(rp)
        .build();
ok2c
  • 26,450
  • 5
  • 63
  • 71
  • 1
    Thanks! It looks like this will work for the regular HttpClient. But it looks like I've stumbled onto a quirk with the HttpAsyncClient. In InternalHttpAsyncClient, the code calls HttpAsyncMethods.create(target, request). This method does an assertion (Args.notNull) on the target variable, and this is invoked before determineRoute gets invoked by MainClientExec.prepare. Since this answers the spirit of my question, I'm marking this as resolved. I'm going to take a look at newer versions of httpclient to see if this is still a problem and will open up an issue if it's still a problem. – weak Nov 25 '13 at 05:10
  • Ahh, silly me. I just noticed that you are the primary maintainer on this project :). How would you prefer I proceed with this? Do you think this is something that should work for AsyncHttpClient? I can log an issue if that is the right thing to do. – weak Nov 25 '13 at 05:16
  • @weak: I think one could still use a custom HttpAsyncRequestProducer that returns null target. Generally, though, null target hosts ought to be avoided so I would not like to relax argument restrictions for HttpAsyncMethods factory methods. If you disagree please raise a JIRA with a change request. – ok2c Nov 25 '13 at 08:23
  • Hi @oleg, I agree with your reasoning so will refrain from opening up a JIRA. We have an abstraction on top of HttpClient in our library, so I just added a method in between our abstraction and HttpClient that first checks if the URI is absolute (`URI.isAbsolute`) and if that is not the case, will provide an absolute URI by using `URIUtils.resolve` to generate a URI with host information. Thanks again for your help :) – weak Nov 25 '13 at 18:52
  • I can't google my way through overriding default HttpAsyncRequestProducer in HttpAsyncClient. @oleg could you give an example code how to overcome this target being null? – TomaszGuzialek Nov 25 '16 at 18:26
  • 1
    Im trying to implement the same in httpclient5. But things are changed a lot. Now this determineRoute method is final and cannot override. Not sure how one can set default target host .. proper documentations is also not there :( – kaluva Jun 10 '21 at 06:50