Index: src/main/java/org/apache/http/impl/client/cache/CachingHttpClient.java =================================================================== --- src/main/java/org/apache/http/impl/client/cache/CachingHttpClient.java (revision 1430006) +++ src/main/java/org/apache/http/impl/client/cache/CachingHttpClient.java (working copy) @@ -909,12 +909,13 @@ log.trace("Handling Backend response"); responseCompliance.ensureProtocolCompliance(request, backendResponse); - + boolean cacheable = responseCachingPolicy.isResponseCacheable(request, backendResponse); responseCache.flushInvalidatedCacheEntriesFor(target, request, backendResponse); if (cacheable && !alreadyHaveNewerCacheEntry(target, request, backendResponse)) { try { + storeRequestIfModifiedSinceFor304Response(request, backendResponse); return responseCache.cacheAndReturnResponse(target, request, backendResponse, requestDate, responseDate); } catch (IOException ioe) { @@ -931,7 +932,23 @@ return backendResponse; } - private boolean alreadyHaveNewerCacheEntry(HttpHost target, HttpRequest request, + /** + * For 304 Not modified responses, adds a "Last-Modified" header with the + * value of the "If-Modified-Since" header passed in the request. This + * header is required to be able to reuse match the cache entry for + * subsequent requests but as defined in http specifications it is not + * included in 304 responses by backend servers. This header will not be + * included in the resulting response. + */ + private void storeRequestIfModifiedSinceFor304Response(HttpRequest request, HttpResponse backendResponse) { + if (backendResponse.getStatusLine().getStatusCode() == HttpStatus.SC_NOT_MODIFIED) { + if (request.containsHeader("If-Modified-Since")) { + backendResponse.addHeader("Last-Modified", request.getFirstHeader("If-Modified-Since").getValue()); + } + } + } + + private boolean alreadyHaveNewerCacheEntry(HttpHost target, HttpRequest request, HttpResponse backendResponse) { HttpCacheEntry existing = null; try { Index: src/test/java/org/apache/http/impl/client/cache/TestCachingHttpClient.java =================================================================== --- src/test/java/org/apache/http/impl/client/cache/TestCachingHttpClient.java (revision 1430006) +++ src/test/java/org/apache/http/impl/client/cache/TestCachingHttpClient.java (working copy) @@ -34,6 +34,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import junit.framework.AssertionFailedError; import org.apache.http.Header; import org.apache.http.HttpEntity; import org.apache.http.HttpHost; @@ -1079,6 +1080,33 @@ } + @Test + public void testReturns304ForIfModifiedSinceHeaderIf304ResponseInCache() throws Exception { + Date now = new Date(); + Date oneHourAgo = new Date(now.getTime() - 3600 * 1000L); + Date inTenMinutes = new Date(now.getTime() + 600 * 1000L); + impl = new CachingHttpClient(mockBackend); + HttpRequest req1 = new HttpGet("http://foo.example.com/"); + req1.addHeader("If-Modified-Since", DateUtils.formatDate(oneHourAgo)); + HttpRequest req2 = new HttpGet("http://foo.example.com/"); + req2.addHeader("If-Modified-Since", DateUtils.formatDate(oneHourAgo)); + + HttpResponse resp1 = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_NOT_MODIFIED, "Not modified"); + resp1.setHeader("Date", DateUtils.formatDate(now)); + resp1.setHeader("Cache-control", "max-age=600"); + resp1.setHeader("Expires", DateUtils.formatDate(inTenMinutes)); + + expect(mockBackend.execute(isA(HttpHost.class), isA(HttpRequest.class), (HttpContext) isNull())).andReturn(resp1).once(); + expect(mockBackend.execute(isA(HttpHost.class), isA(HttpRequest.class), (HttpContext) isNull())).andThrow(new AssertionFailedError("Should have reused cached 304 response")).anyTimes(); + + replayMocks(); + impl.execute(host, req1); + HttpResponse result = impl.execute(host, req2); + verifyMocks(); + Assert.assertEquals(HttpStatus.SC_NOT_MODIFIED, result.getStatusLine().getStatusCode()); + Assert.assertFalse(result.containsHeader("Last-Modified")); + } + @Test public void testReturns200ForIfModifiedSinceDateIsLess() throws Exception { Date now = new Date();