Return-Path: Delivered-To: apmail-hc-commits-archive@www.apache.org Received: (qmail 98839 invoked from network); 12 Jan 2011 19:15:08 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.3) by minotaur.apache.org with SMTP; 12 Jan 2011 19:15:08 -0000 Received: (qmail 20770 invoked by uid 500); 12 Jan 2011 19:15:08 -0000 Delivered-To: apmail-hc-commits-archive@hc.apache.org Received: (qmail 20720 invoked by uid 500); 12 Jan 2011 19:15:08 -0000 Mailing-List: contact commits-help@hc.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: "HttpComponents Project" Delivered-To: mailing list commits@hc.apache.org Received: (qmail 20665 invoked by uid 99); 12 Jan 2011 19:15:08 -0000 Received: from nike.apache.org (HELO nike.apache.org) (192.87.106.230) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 12 Jan 2011 19:15:08 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=10.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 12 Jan 2011 19:15:05 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id C996223889B3; Wed, 12 Jan 2011 19:14:37 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: 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/ Date: Wed, 12 Jan 2011 19:14:37 -0000 To: commits@hc.apache.org From: jonm@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20110112191437.C996223889B3@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org 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 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 requestIsFatallyNonCompliant(HttpRequest request) { List theErrors = new ArrayList(); - //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 outElts = new ArrayList(); + 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 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 cap = new Capture(); + 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 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