Index: src/test/java/org/apache/http/impl/client/cache/TestCachingHttpClient.java =================================================================== --- src/test/java/org/apache/http/impl/client/cache/TestCachingHttpClient.java (revision 1212591) +++ src/test/java/org/apache/http/impl/client/cache/TestCachingHttpClient.java (working copy) @@ -26,6 +26,7 @@ */ package org.apache.http.impl.client.cache; +import java.io.ByteArrayInputStream; import java.io.IOException; import java.net.URI; import java.util.ArrayList; @@ -34,6 +35,7 @@ import java.util.List; import java.util.Map; import org.apache.http.Header; +import org.apache.http.HttpEntity; import org.apache.http.HttpHost; import org.apache.http.HttpRequest; import org.apache.http.HttpResponse; @@ -50,6 +52,7 @@ import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.conn.ClientConnectionManager; +import org.apache.http.entity.InputStreamEntity; import org.apache.http.impl.cookie.DateUtils; import org.apache.http.message.BasicHeader; import org.apache.http.message.BasicHttpRequest; @@ -106,6 +109,7 @@ private HttpContext context; private HttpParams params; private HttpCacheEntry entry; + private ConsumableInputStream cis; @SuppressWarnings("unchecked") @Before @@ -620,15 +624,64 @@ expect(mockHandler.handleResponse(mockBackendResponse)).andReturn( theObject); - + HttpEntity streamingEntity = makeStreamingEntity(); + expect(theResponse.getEntity()).andReturn(streamingEntity); replayMocks(); Object result = impl.execute(host, request, mockHandler, context); verifyMocks(); Assert.assertEquals(1, c.getCount()); Assert.assertSame(theObject, result); + Assert.assertTrue(cis.wasClosed()); } @Test + public void testConsumesEntityOnExecuteWithException() throws Exception { + + final Counter c = new Counter(); + final HttpHost theHost = host; + final HttpRequest theRequest = request; + final HttpResponse theResponse = mockBackendResponse; + final HttpContext theContext = context; + impl = new CachingHttpClient( + mockBackend, + mockValidityPolicy, + mockResponsePolicy, + mockCache, + mockResponseGenerator, + mockRequestPolicy, + mockSuitabilityChecker, + mockConditionalRequestBuilder, + mockResponseProtocolCompliance, + mockRequestProtocolCompliance) { + @Override + public HttpResponse execute(HttpHost target, HttpRequest request, HttpContext context) { + Assert.assertSame(theHost, target); + Assert.assertSame(theRequest, request); + Assert.assertSame(theContext, context); + c.incr(); + return theResponse; + } + }; + IOException ioException = new IOException("test exception"); + + expect(mockHandler.handleResponse(mockBackendResponse)).andThrow(ioException); + HttpEntity streamingEntity = makeStreamingEntity(); + expect(theResponse.getEntity()).andReturn(streamingEntity).anyTimes(); + + replayMocks(); + Object result = null; + try { + result = impl.execute(host, request, mockHandler, context); + } catch (Exception e) { + assertEquals(ioException, e); + } + verifyMocks(); + Assert.assertEquals(1, c.getCount()); + Assert.assertNull(result); + assertTrue(cis.wasClosed()); + } + + @Test public void testCallsSelfWithNullContextOnExecuteUriRequest() throws Exception { final Counter c = new Counter(); final HttpUriRequest theRequest = mockUriRequest; @@ -769,15 +822,16 @@ return theResponse; } }; - expect(mockHandler.handleResponse(mockBackendResponse)).andReturn( theValue); - + HttpEntity streamingEntity = makeStreamingEntity(); + expect(theResponse.getEntity()).andReturn(streamingEntity); replayMocks(); Object result = impl.execute(mockUriRequest, mockHandler, context); verifyMocks(); Assert.assertEquals(1, c.getCount()); Assert.assertSame(theValue, result); + Assert.assertTrue(cis.wasClosed()); } @Test @@ -1941,7 +1995,14 @@ mockRequestProtocolCompliance.makeRequestCompliant( (HttpRequest)anyObject())).andThrow(exception); } - + + private HttpEntity makeStreamingEntity() { + byte[] body = HttpTestUtils.getRandomBytes(101); + ByteArrayInputStream buf = new ByteArrayInputStream(body); + cis = new ConsumableInputStream(buf); + return new InputStreamEntity(cis, 101); + } + private void mockImplMethods(String... methods) { mockedImpl = true; impl = createMockBuilder(CachingHttpClient.class).withConstructor( Index: src/main/java/org/apache/http/impl/client/cache/CachingHttpClient.java =================================================================== --- src/main/java/org/apache/http/impl/client/cache/CachingHttpClient.java (revision 1212593) +++ src/main/java/org/apache/http/impl/client/cache/CachingHttpClient.java (working copy) @@ -27,6 +27,7 @@ package org.apache.http.impl.client.cache; import java.io.IOException; +import java.lang.reflect.UndeclaredThrowableException; import java.net.URI; import java.util.Date; import java.util.HashMap; @@ -337,7 +338,7 @@ public T execute(HttpHost target, HttpRequest request, ResponseHandler responseHandler, HttpContext context) throws IOException { HttpResponse resp = execute(target, request, context); - return responseHandler.handleResponse(resp); + return handleAndConsume(responseHandler,resp); } public HttpResponse execute(HttpUriRequest request) throws IOException { @@ -359,9 +360,48 @@ public T execute(HttpUriRequest request, ResponseHandler responseHandler, HttpContext context) throws IOException { HttpResponse resp = execute(request, context); - return responseHandler.handleResponse(resp); + return handleAndConsume(responseHandler, resp); } + private T handleAndConsume( + final ResponseHandler responseHandler, + HttpResponse response) throws Error, IOException { + T result; + try { + result = responseHandler.handleResponse(response); + } catch (Throwable t) { + HttpEntity entity = response.getEntity(); + try { + + EntityUtils.consume(entity); + } catch (Exception t2) { + // Log this exception. The original exception is more + // important and will be thrown to the caller. + this.log.warn("Error consuming content after an exception.", t2); + } + + if (t instanceof Error) { + throw (Error) t; + } + + if (t instanceof RuntimeException) { + throw (RuntimeException) t; + } + + if (t instanceof IOException) { + throw (IOException) t; + } + + throw new UndeclaredThrowableException(t); + } + + // Handling the response was successful. Ensure that the content has + // been fully consumed. + HttpEntity entity = response.getEntity(); + EntityUtils.consume(entity); + return result; + } + public ClientConnectionManager getConnectionManager() { return backend.getConnectionManager(); }