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