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


git-svn-id: https://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk@1057715 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Jonathan Moore 2011-01-11 16:31:06 +00:00
parent 020d303ec5
commit e95a80b7a2
3 changed files with 150 additions and 10 deletions

View File

@ -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;
}

View File

@ -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 extends AbstractProtocolTest {
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 extends AbstractProtocolTest {
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();
}
}

View File

@ -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,7 +381,66 @@ 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));
}