On Mon, 2023-08-28 at 16:48 -0400, Brent Putman wrote:
> Hi,
> 
> Our project was reviewing a reported resource cleanup issue for
> leaks, 
> and we came across a couple of possibly questionable things in the
> way 
> things are handled in CloseableHttpClient for the response handler 
> variant code below. Wanted to ask for comment. In execute():
> 
>          try (final ClassicHttpResponse response = doExecute(target, 
> request, context)) {
>              try {
>                  final T result =
> responseHandler.handleResponse(response);
>                  final HttpEntity entity = response.getEntity();
>                  EntityUtils.consume(entity);
>                  return result;
>              } catch (final HttpException t) {
>                  // Try to salvage the underlying connection in case
> of 
> a protocol exception
>                  final HttpEntity entity = response.getEntity();
>                  try {
>                      EntityUtils.consume(entity);
>                  } catch (final Exception t2) {
>                      // Log this exception. The original exception is
> more
>                      // important and will be thrown to the caller.
>                      LOG.warn("Error consuming content after an 
> exception.", t2);
>                  }
>                  throw new ClientProtocolException(t);
>              }
>          }
> 

This code is not about connection clean-up, this code is about
connection re-use. The resource clean-up is ensured by closing out the
response.


> First, if the response handler throws an unchecked RuntimeException
> or 
> a Throwable, the EntityUtils.consume(entity) will never get called.
> In 
> order to ensure absolutely that the entity is closed, would it not be
> better to catch Throwable there instead of HttpException?
> 

One should almost never, never, ever catch Throwable. 


> Second, in the implementation of EntityUtils.consume(entity):
> 
>     public static void consume(final HttpEntity entity) throws 
> IOException {
>          if (entity == null) {
>              return;
>          }
>          if (entity.isStreaming()) {
>              Closer.close(entity.getContent());
>          }
>      }
> 
> is there some reason why it calls close() on the entity *content*, 
> rather than on the HttpEntity itself?  The HttpEntity itself is also 
> Closeable, but it itself is never actually closed.
> 

Again, this is about trying to salvage and re-use the connection, not
about resource clean-up. Besides, what usually all entities do in their
#close method is closing their content stream.

Oleg


> Examining all the currently existing HttpEntity impls, it does seem 
> that all of them that are of the streaming type implement their
> close() 
> by merely calling close() on their content... So practically speaking
> the above code isn't "wrong" in terms of behavior of existing impls. 
> But it's also a bit counterintuitive when it would seem more natural
> to 
> just close() the HttpEntity, which will take care of close() on its 
> content if applicable. Also safer in the case of a new (or custom) 
> HttpEntity type which does more in its close() than merely close its 
> content stream.
> 
> Thanks for any insight you can provide. Happy to open a bug report if
> that is more appropriate.
> 
> --Brent

Reply via email to