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 20:14:37 UTC

svn commit: r1058280 - 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 19:14:37 2011
New Revision: 1058280

URL: http://svn.apache.org/viewvc?rev=1058280&view=rev
Log:
Support the following protocol recommendation:

"If a request includes the no-cache directive, it SHOULD NOT
include min-fresh, max-stale, or max-age."

http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.4

We address this by looking for no-cache and then filtering the
above directives out if present.

Added:
    httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestRequestProtocolCompliance.java   (with props)
Modified:
    httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/RequestProtocolCompliance.java
    httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestProtocolRecommendations.java

Modified: httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/RequestProtocolCompliance.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/RequestProtocolCompliance.java?rev=1058280&r1=1058279&r2=1058280&view=diff
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/RequestProtocolCompliance.java (original)
+++ httpcomponents/httpclient/trunk/httpclient-cache/src/main/java/org/apache/http/impl/client/cache/RequestProtocolCompliance.java Wed Jan 12 19:14:37 2011
@@ -27,6 +27,7 @@
 package org.apache.http.impl.client.cache;
 
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 
 import org.apache.http.Header;
@@ -54,6 +55,9 @@ import org.apache.http.protocol.HTTP;
 @Immutable
 class RequestProtocolCompliance {
 
+    private static final List<String> disallowedWithNoCache =
+        Arrays.asList("min-fresh", "max-stale", "max-age");
+
     /**
      * Test to see if the {@link HttpRequest} is HTTP1.1 compliant or not
      * and if not, we can not continue.
@@ -64,11 +68,6 @@ class RequestProtocolCompliance {
     public List<RequestProtocolError> requestIsFatallyNonCompliant(HttpRequest request) {
         List<RequestProtocolError> theErrors = new ArrayList<RequestProtocolError>();
 
-        //RequestProtocolError anError = requestContainsBodyButNoLength(request);
-        //if (anError != null) {
-        //    theErrors.add(anError);
-        //}
-
         RequestProtocolError anError = requestHasWeakETagAndRange(request);
         if (anError != null) {
             theErrors.add(anError);
@@ -105,6 +104,7 @@ class RequestProtocolCompliance {
         verifyRequestWithExpectContinueFlagHas100continueHeader(request);
         verifyOPTIONSRequestWithBodyHasContentType(request);
         decrementOPTIONSMaxForwardsIfGreaterThen0(request);
+        stripOtherFreshnessDirectivesWithNoCache(request);
 
         if (requestVersionIsTooLow(request)) {
             return upgradeRequestTo(request, HttpVersion.HTTP_1_1);
@@ -116,6 +116,38 @@ class RequestProtocolCompliance {
 
         return request;
     }
+    
+    private void stripOtherFreshnessDirectivesWithNoCache(HttpRequest request) {
+        List<HeaderElement> outElts = new ArrayList<HeaderElement>();
+        boolean shouldStrip = false;
+        for(Header h : request.getHeaders("Cache-Control")) {
+            for(HeaderElement elt : h.getElements()) {
+                if (!disallowedWithNoCache.contains(elt.getName())) {
+                    outElts.add(elt);
+                }
+                if ("no-cache".equals(elt.getName())) {
+                    shouldStrip = true;
+                }
+            }
+        }
+        if (!shouldStrip) return;
+        request.removeHeaders("Cache-Control");
+        request.setHeader("Cache-Control", buildHeaderFromElements(outElts));
+    }
+
+    private String buildHeaderFromElements(List<HeaderElement> outElts) {
+        StringBuilder newHdr = new StringBuilder("");
+        boolean first = true;
+        for(HeaderElement elt : outElts) {
+            if (!first) {
+                newHdr.append(",");
+            } else {
+                first = false;
+            }
+            newHdr.append(elt.toString());
+        }
+        return newHdr.toString();
+    }
 
     private boolean requestMustNotHaveEntity(HttpRequest request) {
         return HeaderConstants.TRACE_METHOD.equals(request.getRequestLine().getMethod())

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=1058280&r1=1058279&r2=1058280&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 19:14:37 2011
@@ -30,7 +30,9 @@ import static org.easymock.classextensio
 import static org.junit.Assert.*;
 
 import java.io.IOException;
+import java.util.Arrays;
 import java.util.Date;
+import java.util.List;
 
 import org.apache.http.Header;
 import org.apache.http.HeaderElement;
@@ -1333,4 +1335,43 @@ public class TestProtocolRecommendations
         assertTrue(HttpTestUtils.semanticallyTransparent(resp2, result));
     }
 
+    /*
+     * "If a request includes the no-cache directive, it SHOULD NOT
+     * include min-fresh, max-stale, or max-age."
+     * 
+     * http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.4
+     */
+    @Test
+    public void otherFreshnessRequestDirectivesNotAllowedWithNoCache()
+        throws Exception {
+        HttpRequest req1 = HttpTestUtils.makeDefaultRequest();
+        req1.setHeader("Cache-Control", "min-fresh=10, no-cache");
+        req1.addHeader("Cache-Control", "max-stale=0, max-age=0");
+        
+        Capture<HttpRequest> cap = new Capture<HttpRequest>();
+        expect(mockBackend.execute(same(host), capture(cap), (HttpContext)isNull()))
+            .andReturn(HttpTestUtils.make200Response());
+        
+        replayMocks();
+        impl.execute(host, req1);
+        verifyMocks();
+        
+        HttpRequest captured = cap.getValue();
+        boolean foundNoCache = false;
+        boolean foundDisallowedDirective = false;
+        List<String> disallowed =
+            Arrays.asList("min-fresh", "max-stale", "max-age");
+        for(Header h : captured.getHeaders("Cache-Control")) {
+            for(HeaderElement elt : h.getElements()) {
+                if (disallowed.contains(elt.getName())) {
+                    foundDisallowedDirective = true;
+                }
+                if ("no-cache".equals(elt.getName())) {
+                    foundNoCache = true;
+                }
+            }
+        }
+        assertTrue(foundNoCache);
+        assertFalse(foundDisallowedDirective);
+    }
 }

Added: httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestRequestProtocolCompliance.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestRequestProtocolCompliance.java?rev=1058280&view=auto
==============================================================================
--- httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestRequestProtocolCompliance.java (added)
+++ httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestRequestProtocolCompliance.java Wed Jan 12 19:14:37 2011
@@ -0,0 +1,103 @@
+package org.apache.http.impl.client.cache;
+
+import static org.junit.Assert.*;
+
+import org.apache.http.HttpEntityEnclosingRequest;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpVersion;
+import org.apache.http.ProtocolVersion;
+import org.apache.http.message.BasicHttpEntityEnclosingRequest;
+import org.apache.http.message.BasicHttpRequest;
+import org.junit.Before;
+import org.junit.Test;
+
+public class TestRequestProtocolCompliance {
+
+    private RequestProtocolCompliance impl;
+    private HttpRequest req;
+    private HttpRequest result;
+    
+    @Before
+    public void setUp() {
+        req = HttpTestUtils.makeDefaultRequest();
+        impl = new RequestProtocolCompliance();
+    }
+    
+    @Test
+    public void doesNotModifyACompliantRequest() throws Exception {
+       result = impl.makeRequestCompliant(req); 
+       assertTrue(HttpTestUtils.equivalent(req, result));
+    }
+    
+    @Test
+    public void removesEntityFromTRACERequest() throws Exception {
+        HttpEntityEnclosingRequest req = 
+            new BasicHttpEntityEnclosingRequest("TRACE", "/", HttpVersion.HTTP_1_1);
+        req.setEntity(HttpTestUtils.makeBody(50));
+        result = impl.makeRequestCompliant(req);
+        if (result instanceof HttpEntityEnclosingRequest) {
+            assertNull(((HttpEntityEnclosingRequest)result).getEntity());
+        }
+    }
+    
+    @Test
+    public void upgrades1_0RequestTo1_1() throws Exception {
+        req = new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_0);
+        result = impl.makeRequestCompliant(req);
+        assertEquals(HttpVersion.HTTP_1_1, result.getProtocolVersion());
+    }
+
+    @Test
+    public void downgrades1_2RequestTo1_1() throws Exception {
+        ProtocolVersion HTTP_1_2 = new ProtocolVersion("HTTP", 1, 2);
+        req = new BasicHttpRequest("GET", "/", HTTP_1_2);
+        result = impl.makeRequestCompliant(req);
+        assertEquals(HttpVersion.HTTP_1_1, result.getProtocolVersion());
+    }
+    
+    @Test
+    public void stripsMinFreshFromRequestIfNoCachePresent()
+        throws Exception {
+        req.setHeader("Cache-Control", "no-cache, min-fresh=10");
+        result = impl.makeRequestCompliant(req);
+        assertEquals("no-cache",
+                result.getFirstHeader("Cache-Control").getValue());
+    }
+
+    @Test
+    public void stripsMaxFreshFromRequestIfNoCachePresent()
+        throws Exception {
+        req.setHeader("Cache-Control", "no-cache, max-stale=10");
+        result = impl.makeRequestCompliant(req);
+        assertEquals("no-cache",
+                result.getFirstHeader("Cache-Control").getValue());
+    }
+
+    @Test
+    public void stripsMaxAgeFromRequestIfNoCachePresent()
+        throws Exception {
+        req.setHeader("Cache-Control", "no-cache, max-age=10");
+        result = impl.makeRequestCompliant(req);
+        assertEquals("no-cache",
+                result.getFirstHeader("Cache-Control").getValue());
+    }
+    
+    @Test
+    public void doesNotStripMinFreshFromRequestWithoutNoCache()
+        throws Exception {
+        req.setHeader("Cache-Control", "min-fresh=10");
+        result = impl.makeRequestCompliant(req);
+        assertEquals("min-fresh=10",
+                result.getFirstHeader("Cache-Control").getValue());
+    }
+    
+    @Test
+    public void correctlyStripsMinFreshFromMiddleIfNoCache()
+        throws Exception {
+        req.setHeader("Cache-Control", "no-cache,min-fresh=10,no-store");
+        result = impl.makeRequestCompliant(req);
+        assertEquals("no-cache,no-store",
+                result.getFirstHeader("Cache-Control").getValue());
+    }
+
+}

Propchange: httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestRequestProtocolCompliance.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestRequestProtocolCompliance.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: httpcomponents/httpclient/trunk/httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestRequestProtocolCompliance.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain