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/11 17:31:07 UTC

svn commit: r1057715 - 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: Tue Jan 11 16:31:06 2011
New Revision: 1057715

URL: http://svn.apache.org/viewvc?rev=1057715&view=rev
Log:
Responses from HTTP/1.0 origins to requests containing query parameters
SHOULD NOT be taken from a cache.

http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.9

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=1057715&r1=1057714&r2=1057715&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 Tue Jan 11 16:31:06 2011
@@ -201,7 +201,8 @@ class ResponseCachingPolicy {
             return false;
         }
 
-        if (request.getRequestLine().getUri().contains("?") && !isExplicitlyCacheable(response)) {
+        if (request.getRequestLine().getUri().contains("?") && 
+            (!isExplicitlyCacheable(response) || from1_0Origin(response))) {
             log.debug("Response was not cacheable.");
             return false;
         }
@@ -220,6 +221,21 @@ class ResponseCachingPolicy {
         return isResponseCacheable(method, response);
     }
 
+    private boolean from1_0Origin(HttpResponse response) {
+        Header via = response.getFirstHeader("Via");
+        if (via != null) {
+            for(HeaderElement elt : via.getElements()) {
+                String proto = elt.toString().split("\\s")[0];
+                if (proto.contains("/")) {
+                    return proto.equals("HTTP/1.0"); 
+                } else {
+                    return proto.equals("1.0");
+                }
+            }
+        }
+        return HttpVersion.HTTP_1_0.equals(response.getProtocolVersion());
+    }
+
     private boolean requestProtocolGreaterThanAccepted(HttpRequest req) {
         return req.getProtocolVersion().compareToVersion(HttpVersion.HTTP_1_1) > 0;
     }

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=1057715&r1=1057714&r2=1057715&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 Tue Jan 11 16:31:06 2011
@@ -59,6 +59,7 @@ import org.junit.Test;
  */
 public class TestProtocolRecommendations extends AbstractProtocolTest {
 
+    private Date tenSecondsFromNow;
     private Date now;
     private Date tenSecondsAgo;
     
@@ -68,6 +69,7 @@ public class TestProtocolRecommendations
         super.setUp();
         now = new Date();
         tenSecondsAgo = new Date(now.getTime() - 10 * 1000L);
+        tenSecondsFromNow = new Date(now.getTime() + 10 * 1000L);
     }
     
     /* "identity: The default (identity) encoding; the use of no
@@ -1078,4 +1080,66 @@ public class TestProtocolRecommendations
         impl.execute(host, req3);
         verifyMocks();
     }
+    
+    /*
+     * "This specifically means that responses from HTTP/1.0 servers for such
+     * URIs [those containing a '?' in the rel_path part] SHOULD NOT be taken
+     * from a cache."
+     * 
+     * http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.9
+     */
+    @Test
+    public void responseToGetWithQueryFrom1_0OriginIsNotCached()
+        throws Exception {
+        HttpRequest req1 = new HttpGet("http://foo.example.com/bar?baz=quux");
+        HttpResponse resp1 = new BasicHttpResponse(HttpVersion.HTTP_1_0, HttpStatus.SC_OK, "OK");
+        resp1.setEntity(HttpTestUtils.makeBody(200));
+        resp1.setHeader("Content-Length","200");
+        resp1.setHeader("Date", formatDate(now));
+        resp1.setHeader("Expires", formatDate(tenSecondsFromNow));
+        
+        backendExpectsAnyRequest().andReturn(resp1);
+        
+        HttpRequest req2 = new HttpGet("http://foo.example.com/bar?baz=quux");
+        HttpResponse resp2 = new BasicHttpResponse(HttpVersion.HTTP_1_0, HttpStatus.SC_OK, "OK");
+        resp2.setEntity(HttpTestUtils.makeBody(200));
+        resp2.setHeader("Content-Length","200");
+        resp2.setHeader("Date", formatDate(now));
+        
+        backendExpectsAnyRequest().andReturn(resp2);
+        
+        replayMocks();
+        impl.execute(host, req1);
+        impl.execute(host, req2);
+        verifyMocks();
+    }
+    
+    @Test
+    public void responseToGetWithQueryFrom1_0OriginVia1_1ProxyIsNotCached()
+        throws Exception {
+        HttpRequest req1 = new HttpGet("http://foo.example.com/bar?baz=quux");
+        HttpResponse resp1 = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_OK, "OK");
+        resp1.setEntity(HttpTestUtils.makeBody(200));
+        resp1.setHeader("Content-Length","200");
+        resp1.setHeader("Date", formatDate(now));
+        resp1.setHeader("Expires", formatDate(tenSecondsFromNow));
+        resp1.setHeader("Via","1.0 someproxy");
+        
+        backendExpectsAnyRequest().andReturn(resp1);
+        
+        HttpRequest req2 = new HttpGet("http://foo.example.com/bar?baz=quux");
+        HttpResponse resp2 = new BasicHttpResponse(HttpVersion.HTTP_1_0, HttpStatus.SC_OK, "OK");
+        resp2.setEntity(HttpTestUtils.makeBody(200));
+        resp2.setHeader("Content-Length","200");
+        resp2.setHeader("Date", formatDate(now));
+        resp2.setHeader("Via","1.0 someproxy");
+        
+        backendExpectsAnyRequest().andReturn(resp2);
+        
+        replayMocks();
+        impl.execute(host, req1);
+        impl.execute(host, req2);
+        verifyMocks();
+    }
+
 }

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=1057715&r1=1057714&r2=1057715&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 Tue Jan 11 16:31:06 2011
@@ -32,8 +32,9 @@ import java.util.Random;
 import org.apache.http.HttpRequest;
 import org.apache.http.HttpResponse;
 import org.apache.http.HttpStatus;
+import org.apache.http.HttpVersion;
 import org.apache.http.ProtocolVersion;
-import org.apache.http.impl.cookie.DateUtils;
+import static org.apache.http.impl.cookie.DateUtils.formatDate;
 import org.apache.http.message.BasicHttpRequest;
 import org.apache.http.message.BasicHttpResponse;
 import org.apache.http.message.BasicStatusLine;
@@ -57,7 +58,7 @@ public class TestResponseCachingPolicy {
         request = new BasicHttpRequest("GET","/",HTTP_1_1);
         response = new BasicHttpResponse(
                 new BasicStatusLine(HTTP_1_1, HttpStatus.SC_OK, ""));
-        response.setHeader("Date", DateUtils.formatDate(new Date()));
+        response.setHeader("Date", formatDate(new Date()));
         response.setHeader("Content-Length", "0");
     }
 
@@ -163,7 +164,7 @@ public class TestResponseCachingPolicy {
     public void testNon206WithExplicitExpiresIsCacheable() {
         int status = getRandomStatus();
         response.setStatusCode(status);
-        response.setHeader("Expires", DateUtils.formatDate(new Date()));
+        response.setHeader("Expires", formatDate(new Date()));
         Assert.assertTrue(policy.isResponseCacheable("GET", response));
     }
 
@@ -275,7 +276,7 @@ public class TestResponseCachingPolicy {
 
         response = new BasicHttpResponse(
                 new BasicStatusLine(HTTP_1_1, HttpStatus.SC_OK, ""));
-        response.setHeader("Date", DateUtils.formatDate(new Date()));
+        response.setHeader("Date", formatDate(new Date()));
         response.addHeader("Cache-Control", "no-transform");
         response.setHeader("Content-Length", "0");
 
@@ -333,8 +334,8 @@ public class TestResponseCachingPolicy {
     public void testResponsesWithMultipleDateHeadersAreNotCacheable() {
         Date now = new Date();
         Date sixSecondsAgo = new Date(now.getTime() - 6 * 1000L);
-        response.addHeader("Date", DateUtils.formatDate(now));
-        response.addHeader("Date", DateUtils.formatDate(sixSecondsAgo));
+        response.addHeader("Date", formatDate(now));
+        response.addHeader("Date", formatDate(sixSecondsAgo));
         Assert.assertFalse(policy.isResponseCacheable("GET", response));
     }
 
@@ -348,8 +349,8 @@ public class TestResponseCachingPolicy {
     public void testResponsesWithMultipleExpiresHeadersAreNotCacheable() {
         Date now = new Date();
         Date sixSecondsAgo = new Date(now.getTime() - 6 * 1000L);
-        response.addHeader("Expires", DateUtils.formatDate(now));
-        response.addHeader("Expires", DateUtils.formatDate(sixSecondsAgo));
+        response.addHeader("Expires", formatDate(now));
+        response.addHeader("Expires", formatDate(sixSecondsAgo));
         Assert.assertFalse(policy.isResponseCacheable("GET", response));
     }
 
@@ -380,10 +381,69 @@ public class TestResponseCachingPolicy {
     @Test
     public void testResponsesToGETWithQueryParamsAndExplicitCachingAreCacheable() {
         request = new BasicHttpRequest("GET", "/foo?s=bar");
-        response.setHeader("Expires", DateUtils.formatDate(new Date()));
+        response.setHeader("Expires", formatDate(new Date()));
         Assert.assertTrue(policy.isResponseCacheable(request, response));
     }
 
+    @Test
+    public void getsWithQueryParametersDirectlyFrom1_0OriginsAreNotCacheable() {
+        request = new BasicHttpRequest("GET", "/foo?s=bar");
+        response = new BasicHttpResponse(HttpVersion.HTTP_1_0, HttpStatus.SC_OK, "OK");
+        Assert.assertFalse(policy.isResponseCacheable(request, response));
+    }
+    
+    @Test
+    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));
+    }
+    
+    @Test
+    public void getsWithQueryParametersFrom1_0OriginsViaProxiesAreNotCacheable() {
+        request = new BasicHttpRequest("GET", "/foo?s=bar");
+        response.setHeader("Via", "1.0 someproxy");
+        Assert.assertFalse(policy.isResponseCacheable(request, response));
+    }
+
+    @Test
+    public void getsWithQueryParametersFrom1_0OriginsViaProxiesAreNotCacheableEvenWithExpires() {
+        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", "1.0 someproxy");
+        Assert.assertFalse(policy.isResponseCacheable(request, response));
+    }
+    
+    @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");
+        Assert.assertFalse(policy.isResponseCacheable(request, response));
+    }
+
+    @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));
+        response.setHeader("Via", "1.1 someproxy");
+        Assert.assertTrue(policy.isResponseCacheable(request, response));
+    }
+    
     private int getRandomStatus() {
         int rnd = (new Random()).nextInt(acceptableCodes.length);