74

I have a loop over a bunch of URLs, for each one I'm doing the following:

private String doQuery(String url) {

  HttpGet httpGet = new HttpGet(url);
  setDefaultHeaders(httpGet); // static method
  HttpResponse response = httpClient.execute(httpGet);   // httpClient instantiated in constructor

  int rc = response.getStatusLine().getStatusCode();

  if (rc != 200) {
    // some stuff...
    return;
  }

  HttpEntity entity = response.getEntity();

  if (entity == null) {
    // some stuff...
    return;
  }

  // process the entity, get input stream etc

}

The first query is fine, the second throws this exception:

Exception in thread "main" java.lang.IllegalStateException: Invalid use of SingleClientConnManager: connection still allocated. Make sure to release the connection before allocating another one. at org.apache.http.impl.conn.SingleClientConnManager.getConnection(SingleClientConnManager.java:199) at org.apache.http.impl.conn.SingleClientConnManager$1.getConnection(SingleClientConnManager.java:173)......

This is just a simple single-threaded app. How can I release this connection?

borjab
  • 11,149
  • 6
  • 71
  • 98
Richard H
  • 38,037
  • 37
  • 111
  • 138
  • Related: [Exception using HttpRequest.execute(): Invalid use of SingleClientConnManager: connection still allocated](http://stackoverflow.com/q/4612573) – blahdiblah Feb 20 '13 at 00:18

12 Answers12

99

The recommended way, by Httpcomponents 4.1, is to close connection and release any underlying resources:

EntityUtils.consume(HttpEntity)

where HttpEntity passed is a response entity.

Jérôme Verstrynge
  • 57,710
  • 92
  • 283
  • 453
Yadu
  • 4,891
  • 5
  • 19
  • 12
  • This is the right answer for 4.1. The one from Richard H one does not work for me. – Alexandre Martins Dec 08 '11 at 21:50
  • 1
    I am facing the same problem. This solution works but does not cover all the possible cases. I presume httpClient is being reused. If some requests fail, as you would expect with HTTP, its unclear how to free the allocated resources. Even following the example that Apache provides with multiple different exception handlers, I still face the same issue :( – Rafael Feb 03 '12 at 07:45
  • @Rafael you can use HttpRequestBase.releaseConnection() or HttpUriRequest.abort() if exception is thrown before getting handle of response entity. – Yadu Sep 28 '12 at 21:29
  • 4
    There is no consume method in the EntityUtils class http://developer.android.com/reference/org/apache/http/util/EntityUtils.html – jb11 Feb 18 '14 at 22:40
  • What if there is an exception and in that case closable response object will be null? How do we release the connection is such a scenario if I am not using try with resources? As I can not call response.close() now. Thanks – Jaraws Aug 01 '20 at 20:15
34

This seems to work great :

      if( response.getEntity() != null ) {
         response.getEntity().consumeContent();
      }//if

And don't forget to consume the entity even if you didn't open its content. For instance, you expect a HTTP_OK status from the response and don't get it, you still have to consume the entity !

Snicolas
  • 37,840
  • 15
  • 114
  • 173
  • 13
    consumeContent() is now (4.1.2) deprecated. A one liner instead: EntityUtils.consume(response.getEntity()); – Gili Nachum Nov 19 '12 at 13:33
  • @Snicolas what happens if we did not `consumeContent()` the entity – Kasun Siyambalapitiya Jan 18 '17 at 11:39
  • Not sure but I would say you leak memory. I kinda remember you get an error message too. – Snicolas Jan 20 '17 at 04:10
  • 2
    Followup for those who were wondering: if you don't consume the entity, the HttpClient will consider the request as still in progress. Once enough of these unconsumed requests pile up, subsequent requests will block indefinitely. – Jonathan Fuerth Feb 12 '19 at 14:11
  • seems to be deprecated now – Paul Cuddihy Apr 23 '19 at 20:23
  • What if there is an exception and in that case closable response object will be null? How do we release the connection is such a scenario if I am not using try with resources? As I can not call response.close() now. Thanks – Jaraws Aug 01 '20 at 20:13
24

To answer my own question: to release the connection (and any other resources associated with the request) you must close the InputStream returned by the HttpEntity:

InputStream is = entity.getContent();

.... process the input stream ....

is.close();       // releases all resources

From the docs

Richard H
  • 38,037
  • 37
  • 111
  • 138
  • 3
    I don't think so, I do that and I'm getting "Invalid use of SingleClientConnManager: connection still allocated". it might be done via ClientConnectionManager that I can get from httpClient, but it doesn't seem right – lisak Aug 17 '11 at 14:40
  • neither do I. are you reusing HTTPClient? how do you ensure it releases resources when requests do fail? – Rafael Feb 03 '12 at 07:46
  • 2
    I can confirm that by closing the InputStream I see the debug message: org.apache.http.impl.conn.BasicClientConnectionManager(18314): Releasing connection – Jona Nov 07 '13 at 03:29
  • 1
    I confirm this works fine. Thank You. (btw. using HttpComponents-4.1 "EntityUtils.consume(httpEntity)" does the job also). – Hartmut Pfarr Oct 31 '15 at 18:12
  • Richard is right, calling "close()" on received input stream you notify watcher about closing and then watcher close stream itself and mark connection as "reusable" (httpclient version 4.5.1) – mulya Aug 15 '17 at 09:34
  • "The difference between closing the content stream and closing the response is that the former will attempt to keep the underlying connection alive by consuming the entity content while the latter immediately shuts down and discards the connection." See https://hc.apache.org/httpcomponents-client-ga/tutorial/html/fundamentals.html#d5e145 – JL_SO Sep 24 '20 at 13:22
19

Since version 4.2, they introduced a much more convenience method that simplifies connection release: HttpRequestBase.releaseConnection()

wikier
  • 2,517
  • 2
  • 26
  • 39
13

I'm chiming in with a detailed answer that specifically addresses Apache HttpClient 4.0.1. I'm using this HttpClient version, since it's provided by WAS v8.0, and I need to use that provided HttpClient within Apache Wink v1.1.1, also provided by WAS v8.0, to make some NTLM-authenticated REST calls to Sharepoint.

To quote Oleg Kalnichevski on the Apache HttpClient mailing list:

Pretty much all this code is not necessary. (1) HttpClient will automatically release the underlying connection as long as the entity content is consumed to the end of stream; (2) HttpClient will automatically release the underlying connection on any I/O exception thrown while reading the response content. No special processing is required in such as case.

In fact, this is perfectly sufficient to ensure proper release of resources:

HttpResponse rsp = httpclient.execute(target, req); 
HttpEntity entity = rsp.getEntity(); 
if (entity != null) {
     InputStream instream = entity.getContent();
     try {
         // process content
     } finally {
         instream.close();
         // entity.consumeContent() would also do
     } 
}

That is it.

Source

Youssef NAIT
  • 1,362
  • 11
  • 27
Chris Harris
  • 1,329
  • 4
  • 17
  • 28
  • ...and what happens if the entity is null, what happens then? Don't we need to close the connection? – cecemel Jan 14 '16 at 15:41
  • @cecemel - Well, yes...and however else you want to handle it. It depends on the scope of the situation. – Chris Harris Feb 10 '16 at 21:00
  • 1
    is `EntityUtils.consume(entity)` sufficient? If so, is it same as closing the `instream`? – asgs Nov 13 '16 at 20:44
  • @asgs - I would stick with either of the two lines of code in the finally block. – Chris Harris Nov 14 '16 at 06:10
  • The [`consumeContent` Javadoc](https://hc.apache.org/httpcomponents-core-ga/httpcore/apidocs/org/apache/http/HttpEntity.html#consumeContent()) mentions that it's deprecated and `EntityUtils.consume(entity)` is the way to go. Maybe something changed in between the versions. – asgs Nov 14 '16 at 06:49
  • 1
    @asgs - That depends if the Javadoc is for v4.0.1. I think EntityUtils became the preferred way in a subsequent version after v4.0.1. The mailing list excerpt in my answer is from the time of v4.0.1. – Chris Harris Nov 14 '16 at 22:59
  • Looks like it, Chris. Thank you! – asgs Nov 15 '16 at 06:32
7

If the response is not to be consumed, then the request can be aborted using the code below:

// Low level resources should be released before initiating a new request
HttpEntity entity = response.getEntity();

if (entity != null) {
    // Do not need the rest
    httpPost.abort();
}

Reference: http://hc.apache.org/httpcomponents-client-ga/tutorial/html/fundamentals.html#d5e143

Apache HttpClient Version: 4.1.3

Magnilex
  • 11,584
  • 9
  • 62
  • 84
Jignesh Gohel
  • 6,236
  • 6
  • 53
  • 89
4

I've got this problem when I use HttpClient in Multithread envirnoment (Servlets). One servlet still holds connection and another one want to get connection.

Solution:

version 4.0 use ThreadSafeClientConnManager

version 4.2 use PoolingClientConnectionManager

and set this two setters:

setDefaultMaxPerRoute
setMaxTotal
chris
  • 669
  • 9
  • 16
3

I'm using HttpClient 4.5.3, using CloseableHttpResponse#close worked for me.

    CloseableHttpResponse response = client.execute(request);

    try {
        HttpEntity entity = response.getEntity();
        String body = EntityUtils.toString(entity);
        checkResult(body);
        EntityUtils.consume(entity);
    } finally {
        response.close();
    }

With Java7 and beyond:

try (CloseableHttpResponse response = client.execute(request)) {
   ...
}
Fan Jin
  • 2,412
  • 17
  • 25
  • 2
    From Java 7 on use: `try (CloseableHttpResponse response = client.execute(request)) { ... }` <-- No need to close in finally – Christophe Roussy Nov 22 '17 at 10:34
  • "using CloseableHttpClient#close worked for me." In that code you're closing the response not the client - big difference. – JL_SO Sep 24 '20 at 13:24
  • 1
    @JL_SO closing the response will release the connection from the client back to the connection pool manager. The client can lease another connection at a later time. You need to create a new client instance if you closed the client, which is unnecessary in most cases. – Fan Jin Sep 26 '20 at 21:34
  • @FanJin yes this is true but what I meant was that you said "Client#close worked for me" then pasted code that did Response#close" instead (rather than client#close). – JL_SO Oct 01 '20 at 09:44
  • You are right, and I've updated my answer. – Fan Jin Oct 01 '20 at 16:28
2

HTTP HEAD requests must be treated slightly differently because response.getEntity() is null. Instead, you must capture the HttpContext passed into HttpClient.execute() and retrieve the connection parameter to close it (in HttpComponents 4.1.X anyway).

HttpRequest httpRqst = new HttpHead( uri );
HttpContext httpContext = httpFactory.createContext();
HttpResponse httpResp = httpClient.execute( httpRqst, httpContext );

...

// Close when finished
HttpEntity entity = httpResp.getEntity();
if( null != entity )
  // Handles standard 'GET' case
  EntityUtils.consume( entity );
else {
  ConnectionReleaseTrigger  conn =
      (ConnectionReleaseTrigger) httpContext.getAttribute( ExecutionContext.HTTP_CONNECTION );
  // Handles 'HEAD' where entity is not returned
  if( null != conn )
    conn.releaseConnection();
}

HttpComponents 4.2.X added a releaseConnection() to HttpRequestBase to make this easier.

wbdarby
  • 1,129
  • 12
  • 12
1

If you want to re-use the connection then you must consume content stream completely after every use as follows :

EntityUtils.consume(response.getEntity())

Note : you need to consume the content stream even if the status code is not 200. Not doing so will raise the following on next use :

Exception in thread "main" java.lang.IllegalStateException: Invalid use of SingleClientConnManager: connection still allocated. Make sure to release the connection before allocating another one.

If it's a one time use, then simply closing the connection will release all the resources associated with it.

Ayman Hussain
  • 255
  • 2
  • 2
0

Highly recommend using a handler to handle the response.

client.execute(yourRequest,defaultHanler);

It will release the connection automatically with consume(HTTPENTITY) method.

A handler example:

private ResponseHandler<String> defaultHandler = new ResponseHandler<String>() {
    @Override
    public String handleResponse(HttpResponse response)
        throws IOException {
        int status = response.getStatusLine().getStatusCode();

        if (status >= 200 && status < 300) {
            HttpEntity entity = response.getEntity();
            return entity != null ? EntityUtils.toString(entity) : null;
        } else {
            throw new ClientProtocolException("Unexpected response status: " + status);
        }
    }
};
Lincoln
  • 181
  • 4
-1

I had the same issue and solved it by closing the response at the end of the method:

try {
    // make the request and get the entity 
} catch(final Exception e) {
    // handle the exception
} finally {
    if(response != null) {
        response.close();
    }
}
kerl
  • 270
  • 1
  • 3
  • 17