HTTPCLIENT-1143: CachingHttpClient leaks connections with stale-if-error.

Bugfix from James Miller <jamesmiller01 at gmail dot com>.



git-svn-id: https://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk@1198939 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Jonathan Moore 2011-11-07 21:09:41 +00:00
parent c13bbbdd17
commit c8aafc5c1a
3 changed files with 68 additions and 0 deletions

View File

@ -38,6 +38,7 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.apache.http.Header; import org.apache.http.Header;
import org.apache.http.HeaderElement; import org.apache.http.HeaderElement;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost; import org.apache.http.HttpHost;
import org.apache.http.HttpMessage; import org.apache.http.HttpMessage;
import org.apache.http.HttpRequest; import org.apache.http.HttpRequest;
@ -64,6 +65,7 @@ import org.apache.http.impl.cookie.DateUtils;
import org.apache.http.message.BasicHttpResponse; import org.apache.http.message.BasicHttpResponse;
import org.apache.http.params.HttpParams; import org.apache.http.params.HttpParams;
import org.apache.http.protocol.HttpContext; import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;
import org.apache.http.util.VersionInfo; import org.apache.http.util.VersionInfo;
/** /**
@ -833,6 +835,8 @@ public class CachingHttpClient implements HttpClient {
&& validityPolicy.mayReturnStaleIfError(request, cacheEntry, responseDate)) { && validityPolicy.mayReturnStaleIfError(request, cacheEntry, responseDate)) {
final HttpResponse cachedResponse = responseGenerator.generateResponse(cacheEntry); final HttpResponse cachedResponse = responseGenerator.generateResponse(cacheEntry);
cachedResponse.addHeader(HeaderConstants.WARNING, "110 localhost \"Response is stale\""); cachedResponse.addHeader(HeaderConstants.WARNING, "110 localhost \"Response is stale\"");
HttpEntity errorBody = backendResponse.getEntity();
if (errorBody != null) EntityUtils.consume(errorBody);
return cachedResponse; return cachedResponse;
} }

View File

@ -0,0 +1,32 @@
package org.apache.http.impl.client.cache;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
public class ConsumableInputStream extends InputStream {
private ByteArrayInputStream buf;
private boolean closed = false;
public ConsumableInputStream(ByteArrayInputStream buf) {
this.buf = buf;
}
public int read() throws IOException {
return buf.read();
}
@Override
public void close() {
closed = true;
try {
buf.close();
} catch (IOException e) {
}
}
public boolean wasClosed() {
return closed;
}
}

View File

@ -27,13 +27,17 @@
package org.apache.http.impl.client.cache; package org.apache.http.impl.client.cache;
import static org.junit.Assert.*; import static org.junit.Assert.*;
import java.io.ByteArrayInputStream;
import java.util.Date; import java.util.Date;
import org.apache.http.Header; import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpRequest; import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse; import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus; import org.apache.http.HttpStatus;
import org.apache.http.HttpVersion; import org.apache.http.HttpVersion;
import org.apache.http.entity.InputStreamEntity;
import org.apache.http.impl.cookie.DateUtils; import org.apache.http.impl.cookie.DateUtils;
import org.apache.http.message.BasicHttpRequest; import org.apache.http.message.BasicHttpRequest;
import org.junit.Test; import org.junit.Test;
@ -83,6 +87,34 @@ public class TestRFC5861Compliance extends AbstractProtocolTest {
HttpTestUtils.assert110WarningFound(result); HttpTestUtils.assert110WarningFound(result);
} }
@Test
public void testConsumesErrorResponseWhenServingStale()
throws Exception{
Date tenSecondsAgo = new Date(new Date().getTime() - 10 * 1000L);
HttpRequest req1 = HttpTestUtils.makeDefaultRequest();
HttpResponse resp1 = HttpTestUtils.make200Response(tenSecondsAgo,
"public, max-age=5, stale-if-error=60");
backendExpectsAnyRequest().andReturn(resp1);
HttpRequest req2 = HttpTestUtils.makeDefaultRequest();
HttpResponse resp2 = HttpTestUtils.make500Response();
byte[] body = HttpTestUtils.getRandomBytes(101);
ByteArrayInputStream buf = new ByteArrayInputStream(body);
ConsumableInputStream cis = new ConsumableInputStream(buf);
HttpEntity entity = new InputStreamEntity(cis, 101);
resp2.setEntity(entity);
backendExpectsAnyRequest().andReturn(resp2);
replayMocks();
impl.execute(host,req1);
impl.execute(host,req2);
verifyMocks();
assertTrue(cis.wasClosed());
}
@Test @Test
public void testStaleIfErrorInResponseYieldsToMustRevalidate() public void testStaleIfErrorInResponseYieldsToMustRevalidate()
throws Exception{ throws Exception{