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

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?

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.

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