Index: httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestBasicHttpCache.java =================================================================== --- httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestBasicHttpCache.java (revision 1002242) +++ httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestBasicHttpCache.java (working copy) @@ -33,6 +33,8 @@ import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; +import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.io.InputStream; import java.util.Date; import java.util.HashSet; @@ -50,8 +52,10 @@ import org.apache.http.client.methods.HttpDelete; import org.apache.http.client.methods.HttpGet; import org.apache.http.entity.ByteArrayEntity; +import org.apache.http.entity.StringEntity; import org.apache.http.impl.cookie.DateUtils; import org.apache.http.message.BasicHttpResponse; +import org.apache.http.util.EntityUtils; import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -331,5 +335,34 @@ assertNotNull(result); } + @Test + public void testUpdateCacheReplacesStaleBodyOn200() throws Exception { + HttpHost host = new HttpHost("foo.example.com"); + HttpRequest request = new HttpGet("http://foo.example.com/bar"); + HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK"); + + String newBody = "fdsa"; + response.setEntity(new StringEntity(newBody)); + + HttpCacheEntry cacheEntry = HttpTestUtils.makeCacheEntry("asdf".getBytes()); + + HttpResponse cacheResponse = impl.updateCacheEntry(host, request, cacheEntry, response, new Date(), new Date()); + + Assert.assertEquals(newBody, EntityUtils.toString(cacheResponse.getEntity())); + } + @Test + public void testUpdateCacheRetainsStaleBodyOn304() throws Exception { + HttpHost host = new HttpHost("foo.example.com"); + HttpRequest request = new HttpGet("http://foo.example.com/bar"); + HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_NOT_MODIFIED, "Not Modified"); + + String oldBody = "asdf"; + HttpCacheEntry cacheEntry = HttpTestUtils.makeCacheEntry(oldBody.getBytes()); + + HttpResponse cacheResponse = impl.updateCacheEntry(host, request, cacheEntry, response, new Date(), new Date()); + + Assert.assertEquals(oldBody, EntityUtils.toString(cacheResponse.getEntity())); + } + } Index: httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCacheEntryUpdater.java =================================================================== --- httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCacheEntryUpdater.java (revision 1002701) +++ httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestCacheEntryUpdater.java (working copy) @@ -26,12 +26,21 @@ */ package org.apache.http.impl.client.cache; +import static junit.framework.Assert.assertEquals; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Date; + import org.apache.http.Header; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; import org.apache.http.HttpVersion; import org.apache.http.ProtocolVersion; import org.apache.http.client.cache.HttpCacheEntry; +import org.apache.http.client.cache.Resource; +import org.apache.http.entity.StringEntity; import org.apache.http.impl.cookie.DateUtils; import org.apache.http.message.BasicHeader; import org.apache.http.message.BasicHttpResponse; @@ -40,12 +49,6 @@ import org.junit.Before; import org.junit.Test; -import java.io.IOException; -import java.util.Date; - -import static junit.framework.Assert.assertEquals; -import static junit.framework.Assert.assertNotSame; - public class TestCacheEntryUpdater { private Date requestDate; @@ -62,17 +65,6 @@ } @Test - public void testUpdateCacheEntryReturnsDifferentEntryInstance() throws IOException { - - HttpCacheEntry entry =HttpTestUtils.makeCacheEntry(); - BasicHttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK"); - - HttpCacheEntry newEntry = impl.updateCacheEntry(null, entry, requestDate, responseDate, response); - - assertNotSame(newEntry, entry); - } - - @Test public void testHeadersAreMergedCorrectly() throws IOException { Header[] headers = { @@ -85,13 +77,13 @@ "http", 1, 1), HttpStatus.SC_NOT_MODIFIED, "")); response.setHeaders(new Header[]{}); - HttpCacheEntry updatedEntry = impl.updateCacheEntry(null, cacheEntry, new Date(), new Date(), response); + Header[] mergedHeaders = impl.mergeHeaders(cacheEntry, response); + + Assert.assertEquals(2, mergedHeaders.length); - Assert.assertEquals(2, updatedEntry.getAllHeaders().length); + headersContain(mergedHeaders, "Date", DateUtils.formatDate(responseDate)); + headersContain(mergedHeaders, "ETag", "\"etag\""); - headersContain(updatedEntry.getAllHeaders(), "Date", DateUtils.formatDate(responseDate)); - headersContain(updatedEntry.getAllHeaders(), "ETag", "\"etag\""); - } @Test @@ -110,16 +102,15 @@ new BasicHeader("Last-Modified", DateUtils.formatDate(responseDate)), new BasicHeader("Cache-Control", "public"),}); - HttpCacheEntry updatedEntry = impl.updateCacheEntry(null, cacheEntry, new Date(), new Date(), response); + Header[] mergedHeaders = impl.mergeHeaders(cacheEntry, response); + Assert.assertEquals(4, mergedHeaders.length); - Assert.assertEquals(4, updatedEntry.getAllHeaders().length); - - headersContain(updatedEntry.getAllHeaders(), "Date", DateUtils.formatDate(requestDate)); - headersContain(updatedEntry.getAllHeaders(), "ETag", "\"etag\""); - headersContain(updatedEntry.getAllHeaders(), "Last-Modified", DateUtils + headersContain(mergedHeaders, "Date", DateUtils.formatDate(requestDate)); + headersContain(mergedHeaders, "ETag", "\"etag\""); + headersContain(mergedHeaders, "Last-Modified", DateUtils .formatDate(responseDate)); - headersContain(updatedEntry.getAllHeaders(), "Cache-Control", "public"); + headersContain(mergedHeaders, "Cache-Control", "public"); } @Test @@ -136,41 +127,18 @@ new BasicHeader("Last-Modified", DateUtils.formatDate(responseDate)), new BasicHeader("Cache-Control", "public"),}); - HttpCacheEntry updatedEntry = impl.updateCacheEntry(null, cacheEntry, new Date(), new Date(), response); + Header[] mergedHeaders = impl.mergeHeaders(cacheEntry, response); + Assert.assertEquals(4, mergedHeaders.length); - Assert.assertEquals(4, updatedEntry.getAllHeaders().length); - - headersContain(updatedEntry.getAllHeaders(), "Date", DateUtils.formatDate(requestDate)); - headersContain(updatedEntry.getAllHeaders(), "ETag", "\"etag\""); - headersContain(updatedEntry.getAllHeaders(), "Last-Modified", DateUtils + headersContain(mergedHeaders, "Date", DateUtils.formatDate(requestDate)); + headersContain(mergedHeaders, "ETag", "\"etag\""); + headersContain(mergedHeaders, "Last-Modified", DateUtils .formatDate(responseDate)); - headersContain(updatedEntry.getAllHeaders(), "Cache-Control", "public"); + headersContain(mergedHeaders, "Cache-Control", "public"); } - @Test - public void testUpdatedEntryHasLatestRequestAndResponseDates() throws IOException { - - Date now = new Date(); - - Date tenSecondsAgo = new Date(now.getTime() - 10000L); - Date eightSecondsAgo = new Date(now.getTime() - 8000L); - - Date twoSecondsAgo = new Date(now.getTime() - 2000L); - Date oneSecondAgo = new Date(now.getTime() - 1000L); - - HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(tenSecondsAgo, eightSecondsAgo); - - HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, 200, "OK"); - - HttpCacheEntry updated = impl.updateCacheEntry(null, entry, twoSecondsAgo, oneSecondAgo, response); - - assertEquals(twoSecondsAgo, updated.getRequestDate()); - assertEquals(oneSecondAgo, updated.getResponseDate()); - - } - private void headersContain(Header[] headers, String name, String value) { for (Header header : headers) { if (header.getName().equals(name)) { @@ -181,5 +149,5 @@ } Assert.fail("Header [" + name + ": " + value + "] not found in headers."); } - + } Index: httpclient-cache/src/main/java/org/apache/http/impl/client/cache/BasicHttpCache.java =================================================================== --- httpclient-cache/src/main/java/org/apache/http/impl/client/cache/BasicHttpCache.java (revision 1002242) +++ httpclient-cache/src/main/java/org/apache/http/impl/client/cache/BasicHttpCache.java (working copy) @@ -38,7 +38,7 @@ public BasicHttpCache(ResourceFactory resourceFactory, HttpCacheStorage storage, CacheConfig config) { this.resourceFactory = resourceFactory; this.uriExtractor = new URIExtractor(); - this.cacheEntryUpdater = new CacheEntryUpdater(resourceFactory); + this.cacheEntryUpdater = new CacheEntryUpdater(); this.maxObjectSizeBytes = config.getMaxObjectSizeBytes(); this.responseGenerator = new CachedHttpResponseGenerator(); this.storage = storage; @@ -155,14 +155,21 @@ public HttpResponse updateCacheEntry(HttpHost target, HttpRequest request, HttpCacheEntry stale, HttpResponse originResponse, Date requestSent, Date responseReceived) throws IOException { - HttpCacheEntry updatedEntry = cacheEntryUpdater.updateCacheEntry( - request.getRequestLine().getUri(), - stale, - requestSent, - responseReceived, - originResponse); - storeInCache(target, request, updatedEntry); - return responseGenerator.generateResponse(updatedEntry); + if (originResponse.getStatusLine().getStatusCode() == HttpStatus.SC_NOT_MODIFIED) { + Header[] mergedHeaders = cacheEntryUpdater.mergeHeaders(stale, originResponse); + Resource resource = resourceFactory.copy(request.getRequestLine().getUri(), stale.getResource()); + HttpCacheEntry updatedEntry = new HttpCacheEntry( + requestSent, + responseReceived, + stale.getStatusLine(), + mergedHeaders, + resource, + null); + storeInCache(target, request, updatedEntry); + return responseGenerator.generateResponse(updatedEntry); + } + + return cacheAndReturnResponse(target, request, originResponse, requestSent, responseReceived); } public HttpResponse cacheAndReturnResponse(HttpHost host, HttpRequest request, Index: httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheEntryUpdater.java =================================================================== --- httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheEntryUpdater.java (revision 1002242) +++ httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheEntryUpdater.java (working copy) @@ -26,7 +26,6 @@ */ package org.apache.http.impl.client.cache; -import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; @@ -38,8 +37,6 @@ import org.apache.http.annotation.Immutable; import org.apache.http.client.cache.HeaderConstants; import org.apache.http.client.cache.HttpCacheEntry; -import org.apache.http.client.cache.Resource; -import org.apache.http.client.cache.ResourceFactory; import org.apache.http.impl.cookie.DateParseException; import org.apache.http.impl.cookie.DateUtils; import org.apache.http.protocol.HTTP; @@ -53,47 +50,10 @@ */ @Immutable class CacheEntryUpdater { - - private final ResourceFactory resourceFactory; - + CacheEntryUpdater() { - this(new HeapResourceFactory()); } - CacheEntryUpdater(final ResourceFactory resourceFactory) { - super(); - this.resourceFactory = resourceFactory; - } - - /** - * Update the entry with the new information from the response. - * - * @param request id - * @param entry The cache Entry to be updated - * @param requestDate When the request was performed - * @param responseDate When the response was gotten - * @param response The HttpResponse from the backend server call - * @return HttpCacheEntry an updated version of the cache entry - * @throws java.io.IOException if something bad happens while trying to read the body from the original entry - */ - public HttpCacheEntry updateCacheEntry( - String requestId, - HttpCacheEntry entry, - Date requestDate, - Date responseDate, - HttpResponse response) throws IOException { - - Header[] mergedHeaders = mergeHeaders(entry, response); - Resource resource = resourceFactory.copy(requestId, entry.getResource()); - return new HttpCacheEntry( - requestDate, - responseDate, - entry.getStatusLine(), - mergedHeaders, - resource, - null); - } - protected Header[] mergeHeaders(HttpCacheEntry entry, HttpResponse response) { List
cacheEntryHeaderList = new ArrayList
(Arrays.asList(entry .getAllHeaders())); Index: httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachingHttpClient.java =================================================================== --- httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachingHttpClient.java (revision 1002242) +++ httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CachingHttpClient.java (working copy) @@ -558,6 +558,7 @@ } } + backendResponse.addHeader("Via", generateViaHeader(backendResponse)); int statusCode = backendResponse.getStatusLine().getStatusCode(); if (statusCode == HttpStatus.SC_NOT_MODIFIED || statusCode == HttpStatus.SC_OK) {