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. git-svn-id: https://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk@1058280 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
3daa07005e
commit
b4d6dee028
|
@ -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())
|
||||
|
|
|
@ -30,7 +30,9 @@ import static org.easymock.classextension.EasyMock.*;
|
|||
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 extends AbstractProtocolTest {
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
|
103
httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestRequestProtocolCompliance.java
vendored
Normal file
103
httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestRequestProtocolCompliance.java
vendored
Normal file
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue