You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hc.apache.org by jo...@apache.org on 2011/01/12 18:35:29 UTC
svn commit: r1058247 - in
/httpcomponents/httpclient/trunk/httpclient-cache/src:
main/java/org/apache/http/impl/client/cache/
test/java/org/apache/http/impl/client/cache/
Author: jonm
Date: Wed Jan 12 17:35:29 2011
New Revision: 1058247
URL: http://svn.apache.org/viewvc?rev=1058247&view=rev
Log:
Implementation fix and acceptance tests for protocol recommendation:
"Many HTTP/1.0 cache implementations will treat an Expires value that
is less than or equal to the response Date value as being equivalent
to the Cache-Control response directive "no-cache". If an HTTP/1.1
cache receives such a response, and the response does not include a
Cache-Control header field, it SHOULD consider the response to be non-
cacheable in order to retain compatibility with HTTP/1.0 servers."
http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.3
Also had to update a few other test cases that incidentally ran afoul
of this recommendation.
Modified:
httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ResponseCachingPolicy.java
httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestProtocolRecommendations.java
httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestResponseCachingPolicy.java
Modified: httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ResponseCachingPolicy.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ResponseCachingPolicy.java?rev=1058247&r1=1058246&r2=1058247&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ResponseCachingPolicy.java (original)
+++ httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ResponseCachingPolicy.java Wed Jan 12 17:35:29 2011
@@ -26,6 +26,8 @@
*/
package org.apache.http.impl.client.cache;
+import java.util.Date;
+
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.Header;
@@ -196,6 +198,7 @@ class ResponseCachingPolicy {
log.debug("Response was not cacheable.");
return false;
}
+
String[] uncacheableRequestDirectives = { "no-store" };
if (hasCacheControlParameterFrom(request,uncacheableRequestDirectives)) {
return false;
@@ -207,6 +210,10 @@ class ResponseCachingPolicy {
return false;
}
+ if (expiresHeaderLessOrEqualToDateHeaderAndNoCacheControl(response)) {
+ return false;
+ }
+
if (sharedCache) {
Header[] authNHeaders = request.getHeaders("Authorization");
if (authNHeaders != null && authNHeaders.length > 0) {
@@ -221,6 +228,21 @@ class ResponseCachingPolicy {
return isResponseCacheable(method, response);
}
+ private boolean expiresHeaderLessOrEqualToDateHeaderAndNoCacheControl(
+ HttpResponse response) {
+ if (response.getFirstHeader("Cache-Control") != null) return false;
+ Header expiresHdr = response.getFirstHeader("Expires");
+ Header dateHdr = response.getFirstHeader("Date");
+ if (expiresHdr == null || dateHdr == null) return false;
+ try {
+ Date expires = DateUtils.parseDate(expiresHdr.getValue());
+ Date date = DateUtils.parseDate(dateHdr.getValue());
+ return expires.equals(date) || expires.before(date);
+ } catch (DateParseException dpe) {
+ return false;
+ }
+ }
+
private boolean from1_0Origin(HttpResponse response) {
Header via = response.getFirstHeader("Via");
if (via != null) {
Modified: httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestProtocolRecommendations.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestProtocolRecommendations.java?rev=1058247&r1=1058246&r2=1058247&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestProtocolRecommendations.java (original)
+++ httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestProtocolRecommendations.java Wed Jan 12 17:35:29 2011
@@ -717,6 +717,7 @@ public class TestProtocolRecommendations
resp1.setHeader("ETag","\"etag\"");
resp1.setHeader("Date", formatDate(now));
resp1.setHeader("Expires",formatDate(oneSecondAgo));
+ resp1.setHeader("Cache-Control", "public");
backendExpectsAnyRequest().andReturn(resp1);
@@ -1268,4 +1269,68 @@ public class TestProtocolRecommendations
assertTrue(HttpTestUtils.semanticallyTransparent(resp2, result));
}
+
+ /*
+ * "Many HTTP/1.0 cache implementations will treat an Expires value
+ * that is less than or equal to the response Date value as being
+ * equivalent to the Cache-Control response directive 'no-cache'.
+ * If an HTTP/1.1 cache receives such a response, and the response
+ * does not include a Cache-Control header field, it SHOULD consider
+ * the response to be non-cacheable in order to retain compatibility
+ * with HTTP/1.0 servers."
+ *
+ * http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.3
+ */
+ @Test
+ public void expiresEqualToDateWithNoCacheControlIsNotCacheable()
+ throws Exception {
+ HttpRequest req1 = HttpTestUtils.makeDefaultRequest();
+ HttpResponse resp1 = HttpTestUtils.make200Response();
+ resp1.setHeader("Date", formatDate(now));
+ resp1.setHeader("Expires", formatDate(now));
+ resp1.removeHeaders("Cache-Control");
+
+ backendExpectsAnyRequest().andReturn(resp1);
+
+ HttpRequest req2 = HttpTestUtils.makeDefaultRequest();
+ req2.setHeader("Cache-Control", "max-stale=1000");
+ HttpResponse resp2 = HttpTestUtils.make200Response();
+ resp2.setHeader("ETag", "\"etag2\"");
+
+ backendExpectsAnyRequest().andReturn(resp2);
+
+ replayMocks();
+ impl.execute(host, req1);
+ HttpResponse result = impl.execute(host, req2);
+ verifyMocks();
+
+ assertTrue(HttpTestUtils.semanticallyTransparent(resp2, result));
+ }
+
+ @Test
+ public void expiresPriorToDateWithNoCacheControlIsNotCacheable()
+ throws Exception {
+ HttpRequest req1 = HttpTestUtils.makeDefaultRequest();
+ HttpResponse resp1 = HttpTestUtils.make200Response();
+ resp1.setHeader("Date", formatDate(now));
+ resp1.setHeader("Expires", formatDate(tenSecondsAgo));
+ resp1.removeHeaders("Cache-Control");
+
+ backendExpectsAnyRequest().andReturn(resp1);
+
+ HttpRequest req2 = HttpTestUtils.makeDefaultRequest();
+ req2.setHeader("Cache-Control", "max-stale=1000");
+ HttpResponse resp2 = HttpTestUtils.make200Response();
+ resp2.setHeader("ETag", "\"etag2\"");
+
+ backendExpectsAnyRequest().andReturn(resp2);
+
+ replayMocks();
+ impl.execute(host, req1);
+ HttpResponse result = impl.execute(host, req2);
+ verifyMocks();
+
+ assertTrue(HttpTestUtils.semanticallyTransparent(resp2, result));
+ }
+
}
Modified: httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestResponseCachingPolicy.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestResponseCachingPolicy.java?rev=1058247&r1=1058246&r2=1058247&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestResponseCachingPolicy.java (original)
+++ httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestResponseCachingPolicy.java Wed Jan 12 17:35:29 2011
@@ -51,9 +51,16 @@ public class TestResponseCachingPolicy {
private int[] acceptableCodes = new int[] { HttpStatus.SC_OK,
HttpStatus.SC_NON_AUTHORITATIVE_INFORMATION, HttpStatus.SC_MULTIPLE_CHOICES,
HttpStatus.SC_MOVED_PERMANENTLY, HttpStatus.SC_GONE };
+ private Date now;
+ private Date tenSecondsFromNow;
+ private Date sixSecondsAgo;
@Before
public void setUp() throws Exception {
+ now = new Date();
+ sixSecondsAgo = new Date(now.getTime() - 6 * 1000L);
+ tenSecondsFromNow = new Date(now.getTime() + 10 * 1000L);
+
policy = new ResponseCachingPolicy(0, true);
request = new BasicHttpRequest("GET","/",HTTP_1_1);
response = new BasicHttpResponse(
@@ -332,8 +339,6 @@ public class TestResponseCachingPolicy {
@Test
public void testResponsesWithMultipleDateHeadersAreNotCacheable() {
- Date now = new Date();
- Date sixSecondsAgo = new Date(now.getTime() - 6 * 1000L);
response.addHeader("Date", formatDate(now));
response.addHeader("Date", formatDate(sixSecondsAgo));
Assert.assertFalse(policy.isResponseCacheable("GET", response));
@@ -381,7 +386,8 @@ public class TestResponseCachingPolicy {
@Test
public void testResponsesToGETWithQueryParamsAndExplicitCachingAreCacheable() {
request = new BasicHttpRequest("GET", "/foo?s=bar");
- response.setHeader("Expires", formatDate(new Date()));
+ response.setHeader("Date", formatDate(now));
+ response.setHeader("Expires", formatDate(tenSecondsFromNow));
Assert.assertTrue(policy.isResponseCacheable(request, response));
}
@@ -396,8 +402,6 @@ public class TestResponseCachingPolicy {
public void getsWithQueryParametersDirectlyFrom1_0OriginsAreNotCacheableEvenWithExpires() {
request = new BasicHttpRequest("GET", "/foo?s=bar");
response = new BasicHttpResponse(HttpVersion.HTTP_1_0, HttpStatus.SC_OK, "OK");
- Date now = new Date();
- Date tenSecondsFromNow = new Date(now.getTime() + 10 * 1000L);
response.setHeader("Date", formatDate(now));
response.setHeader("Expires", formatDate(tenSecondsFromNow));
Assert.assertFalse(policy.isResponseCacheable(request, response));
@@ -424,8 +428,6 @@ public class TestResponseCachingPolicy {
@Test
public void getsWithQueryParametersFrom1_0OriginsViaExplicitProxiesAreNotCacheableEvenWithExpires() {
request = new BasicHttpRequest("GET", "/foo?s=bar");
- Date now = new Date();
- Date tenSecondsFromNow = new Date(now.getTime() + 10 * 1000L);
response.setHeader("Date", formatDate(now));
response.setHeader("Expires", formatDate(tenSecondsFromNow));
response.setHeader("Via", "HTTP/1.0 someproxy");
@@ -435,8 +437,6 @@ public class TestResponseCachingPolicy {
@Test
public void getsWithQueryParametersFrom1_1OriginsVia1_0ProxiesAreCacheableWithExpires() {
request = new BasicHttpRequest("GET", "/foo?s=bar");
- Date now = new Date();
- Date tenSecondsFromNow = new Date(now.getTime() + 10 * 1000L);
response = new BasicHttpResponse(HttpVersion.HTTP_1_0, HttpStatus.SC_OK, "OK");
response.setHeader("Date", formatDate(now));
response.setHeader("Expires", formatDate(tenSecondsFromNow));
@@ -444,6 +444,22 @@ public class TestResponseCachingPolicy {
Assert.assertTrue(policy.isResponseCacheable(request, response));
}
+ @Test
+ public void notCacheableIfExpiresEqualsDateAndNoCacheControl() {
+ response.setHeader("Date", formatDate(now));
+ response.setHeader("Expires", formatDate(now));
+ response.removeHeaders("Cache-Control");
+ Assert.assertFalse(policy.isResponseCacheable(request, response));
+ }
+
+ @Test
+ public void notCacheableIfExpiresPrecedesDateAndNoCacheControl() {
+ response.setHeader("Date", formatDate(now));
+ response.setHeader("Expires", formatDate(sixSecondsAgo));
+ response.removeHeaders("Cache-Control");
+ Assert.assertFalse(policy.isResponseCacheable(request, response));
+ }
+
private int getRandomStatus() {
int rnd = (new Random()).nextInt(acceptableCodes.length);