Koray Tugay
Koray Tugay

Reputation: 23800

Apache Http Components - How to timeout CONNECT request to a proxy?

Timeout Without Using Proxy

I start netcat in my local as follows, which basically listens to connections on port 9090:

netcat -l -p 9090

And using Apache HttpComponents, I create a connection to it with a timeout of 4 seconds..

RequestConfig requestConfig = RequestConfig.custom()
        .setSocketTimeout(4000)
        .setConnectTimeout(4000)
        .setConnectionRequestTimeout(4000)
        .build();

HttpGet httpget = new HttpGet("http://127.0.0.1:9090");
httpget.setConfig(requestConfig);

try (CloseableHttpResponse response = HttpClients.createDefault().execute(httpget)) {}

In terminal (where I have netcat running) I see:

??]?D???;#???9?Mۡ?NR?w?{)?V?$?(=?&?*kj?
?5??98?#?'<?%?)g@?  ?/??32?,?+?0??.?2???/??-?1???D

<!-- 4 seconds later -->
read(net): Connection reset by peer

In client side what I see is:

Exception in thread "main" org.apache.http.conn.ConnectTimeoutException: 
Connect to 127.0.0.1:9090 [/127.0.0.1] failed: Read timed out

This is all expected.

Timeout Using Proxy

I change the client code slightly and configure a proxy, following the docs here.

RequestConfig requestConfig = RequestConfig.custom()
         .setSocketTimeout(4000)
         .setConnectTimeout(4000)
         .setConnectionRequestTimeout(4000)
         .build();

HttpHost proxy = new HttpHost("127.0.0.1", 9090);
DefaultProxyRoutePlanner routePlanner = new DefaultProxyRoutePlanner(proxy);
CloseableHttpClient httpclient = HttpClients.custom()
        .setRoutePlanner(routePlanner)
        .build();

HttpGet httpget = new HttpGet("https://127.0.0.1:9090");
httpget.setConfig(requestConfig);

try (CloseableHttpResponse response = httpclient.execute(httpget)) {}

And again start netcat, and this time on serverside

CONNECT 127.0.0.1:9090 HTTP/1.1
Host: 127.0.0.1:9090
User-Agent: Apache-HttpClient/4.4.1 (Java/1.8.0_212)

But timeout is not working for CONNECT. I just wait forever..

How can I configure the httpclient to timeout for 4 seconds just like in the first case I described?

Upvotes: 2

Views: 1300

Answers (2)

Koray Tugay
Koray Tugay

Reputation: 23800

One possibility:

// This part is the same..
httpget.setConfig(requestConfig);

ExecutorService executorService = Executors.newSingleThreadExecutor();
Callable<CloseableHttpResponse> callable = () -> {
    try (CloseableHttpResponse response = httpclient.execute(httpget)) {
        return response;
    }
};

Future<CloseableHttpResponse> future = executorService.submit(callable);
try {
    future.get(4, TimeUnit.SECONDS);
} catch (InterruptedException | ExecutionException | TimeoutException e) {
    httpget.abort();
    executorService.shutdownNow();
}

But I am open to other suggestions..

Upvotes: 0

ok2c
ok2c

Reputation: 27538

RequestConfig only take effect once a connection to the target via the specific route has been fully established . They do not apply to the SSL handshake or any CONNECT requests that take place prior to the main message exchange.

Configure socket timeout at the ConnectionManager level to ensure connection level operations time out after a certain period of inactivity.

Upvotes: 3

Related Questions