View Javadoc
1   /*
2    * ====================================================================
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   *   http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing,
14   * software distributed under the License is distributed on an
15   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16   * KIND, either express or implied.  See the License for the
17   * specific language governing permissions and limitations
18   * under the License.
19   * ====================================================================
20   *
21   * This software consists of voluntary contributions made by many
22   * individuals on behalf of the Apache Software Foundation.  For more
23   * information on the Apache Software Foundation, please see
24   * <http://www.apache.org/>.
25   *
26   */
27  package org.apache.hc.client5.http.impl.cache;
28  
29  import java.time.Instant;
30  import java.util.Random;
31  
32  import org.apache.hc.client5.http.auth.StandardAuthScheme;
33  import org.apache.hc.client5.http.classic.methods.HttpOptions;
34  import org.apache.hc.client5.http.utils.DateUtils;
35  import org.apache.hc.core5.http.HttpRequest;
36  import org.apache.hc.core5.http.HttpResponse;
37  import org.apache.hc.core5.http.HttpStatus;
38  import org.apache.hc.core5.http.HttpVersion;
39  import org.apache.hc.core5.http.ProtocolVersion;
40  import org.apache.hc.core5.http.message.BasicHttpRequest;
41  import org.apache.hc.core5.http.message.BasicHttpResponse;
42  import org.junit.jupiter.api.Assertions;
43  import org.junit.jupiter.api.BeforeEach;
44  import org.junit.jupiter.api.Test;
45  
46  public class TestResponseCachingPolicy {
47  
48      private static final ProtocolVersion HTTP_1_1 = new ProtocolVersion("HTTP", 1, 1);
49      private ResponseCachingPolicy policy;
50      private HttpResponse response;
51      private HttpRequest request;
52      private final int[] acceptableCodes = new int[] { HttpStatus.SC_OK,
53              HttpStatus.SC_NON_AUTHORITATIVE_INFORMATION, HttpStatus.SC_MULTIPLE_CHOICES,
54              HttpStatus.SC_MOVED_PERMANENTLY, HttpStatus.SC_GONE };
55      private Instant now;
56      private Instant tenSecondsFromNow;
57      private Instant sixSecondsAgo;
58  
59      @BeforeEach
60      public void setUp() throws Exception {
61          now = Instant.now();
62          sixSecondsAgo = now.minusSeconds(6);
63          tenSecondsFromNow = now.plusSeconds(10);
64  
65          policy = new ResponseCachingPolicy(0, true, false, false);
66          request = new BasicHttpRequest("GET","/");
67          response = new BasicHttpResponse(HttpStatus.SC_OK, "");
68          response.setHeader("Date", DateUtils.formatStandardDate(Instant.now()));
69          response.setHeader("Content-Length", "0");
70      }
71  
72      @Test
73      public void testIsGetCacheable() {
74          Assertions.assertTrue(policy.isResponseCacheable("GET", response));
75      }
76  
77      @Test
78      public void testIsHeadCacheable() {
79          policy = new ResponseCachingPolicy(0, true, false, false);
80          Assertions.assertTrue(policy.isResponseCacheable("HEAD", response));
81      }
82  
83      @Test
84      public void testResponsesToRequestsWithAuthorizationHeadersAreNotCacheableBySharedCache() {
85          request = new BasicHttpRequest("GET","/");
86          request.setHeader("Authorization", StandardAuthScheme.BASIC + " dXNlcjpwYXNzd2Q=");
87          Assertions.assertFalse(policy.isResponseCacheable(request,response));
88      }
89  
90      @Test
91      public void testResponsesToRequestsWithAuthorizationHeadersAreCacheableByNonSharedCache() {
92          policy = new ResponseCachingPolicy(0, false, false, false);
93          request = new BasicHttpRequest("GET","/");
94          request.setHeader("Authorization", StandardAuthScheme.BASIC + " dXNlcjpwYXNzd2Q=");
95          Assertions.assertTrue(policy.isResponseCacheable(request,response));
96      }
97  
98      @Test
99      public void testAuthorizedResponsesWithSMaxAgeAreCacheable() {
100         request = new BasicHttpRequest("GET","/");
101         request.setHeader("Authorization", StandardAuthScheme.BASIC + " dXNlcjpwYXNzd2Q=");
102         response.setHeader("Cache-Control","s-maxage=3600");
103         Assertions.assertTrue(policy.isResponseCacheable(request,response));
104     }
105 
106     @Test
107     public void testAuthorizedResponsesWithMustRevalidateAreCacheable() {
108         request = new BasicHttpRequest("GET","/");
109         request.setHeader("Authorization", StandardAuthScheme.BASIC + " dXNlcjpwYXNzd2Q=");
110         response.setHeader("Cache-Control","must-revalidate");
111         Assertions.assertTrue(policy.isResponseCacheable(request,response));
112     }
113 
114     @Test
115     public void testAuthorizedResponsesWithCacheControlPublicAreCacheable() {
116         request = new BasicHttpRequest("GET","/");
117         request.setHeader("Authorization", StandardAuthScheme.BASIC + " dXNlcjpwYXNzd2Q=");
118         response.setHeader("Cache-Control","public");
119         Assertions.assertTrue(policy.isResponseCacheable(request,response));
120     }
121 
122     @Test
123     public void testAuthorizedResponsesWithCacheControlMaxAgeAreNotCacheable() {
124         request = new BasicHttpRequest("GET","/");
125         request.setHeader("Authorization", StandardAuthScheme.BASIC + " dXNlcjpwYXNzd2Q=");
126         response.setHeader("Cache-Control","max-age=3600");
127         Assertions.assertFalse(policy.isResponseCacheable(request,response));
128     }
129 
130     @Test
131     public void test203ResponseCodeIsCacheable() {
132         response.setCode(HttpStatus.SC_NON_AUTHORITATIVE_INFORMATION);
133         Assertions.assertTrue(policy.isResponseCacheable("GET", response));
134     }
135 
136     @Test
137     public void test206ResponseCodeIsNotCacheable() {
138         response.setCode(HttpStatus.SC_PARTIAL_CONTENT);
139         Assertions.assertFalse(policy.isResponseCacheable("GET", response));
140     }
141 
142     @Test
143     public void test206ResponseCodeIsNotCacheableUsingSharedPublicCache() {
144         policy = new ResponseCachingPolicy(0, true, false, false);
145 
146         request.setHeader("Authorization", StandardAuthScheme.BASIC + " QWxhZGRpbjpvcGVuIHNlc2FtZQ==");
147         response.setCode(HttpStatus.SC_PARTIAL_CONTENT);
148         response.setHeader("Cache-Control", "public");
149         Assertions.assertFalse(policy.isResponseCacheable(request, response));
150     }
151 
152     @Test
153     public void test300ResponseCodeIsCacheable() {
154         response.setCode(HttpStatus.SC_MULTIPLE_CHOICES);
155         Assertions.assertTrue(policy.isResponseCacheable("GET", response));
156     }
157 
158     @Test
159     public void test301ResponseCodeIsCacheable() {
160         response.setCode(HttpStatus.SC_MOVED_PERMANENTLY);
161         Assertions.assertTrue(policy.isResponseCacheable("GET", response));
162     }
163 
164     @Test
165     public void test410ResponseCodeIsCacheable() {
166         response.setCode(HttpStatus.SC_GONE);
167         Assertions.assertTrue(policy.isResponseCacheable("GET", response));
168     }
169 
170     @Test
171     public void testPlain302ResponseCodeIsNotCacheable() {
172         response.setCode(HttpStatus.SC_MOVED_TEMPORARILY);
173         response.removeHeaders("Expires");
174         response.removeHeaders("Cache-Control");
175         Assertions.assertFalse(policy.isResponseCacheable("GET", response));
176     }
177 
178     @Test
179     public void testPlain303ResponseCodeIsNotCacheableUnderDefaultBehavior() {
180         response.setCode(HttpStatus.SC_SEE_OTHER);
181         response.removeHeaders("Expires");
182         response.removeHeaders("Cache-Control");
183         Assertions.assertFalse(policy.isResponseCacheable("GET", response));
184     }
185 
186     @Test
187     public void testPlain303ResponseCodeIsNotCacheableEvenIf303CachingEnabled() {
188         policy = new ResponseCachingPolicy(0, true, false, true);
189         response.setCode(HttpStatus.SC_SEE_OTHER);
190         response.removeHeaders("Expires");
191         response.removeHeaders("Cache-Control");
192         Assertions.assertFalse(policy.isResponseCacheable("GET", response));
193     }
194 
195 
196     @Test
197     public void testPlain307ResponseCodeIsNotCacheable() {
198         response.setCode(HttpStatus.SC_TEMPORARY_REDIRECT);
199         response.removeHeaders("Expires");
200         response.removeHeaders("Cache-Control");
201         Assertions.assertFalse(policy.isResponseCacheable("GET", response));
202     }
203 
204     @Test
205     public void testNon206WithExplicitExpiresIsCacheable() {
206         final int status = getRandomStatus();
207         response.setCode(status);
208         response.setHeader("Expires", DateUtils.formatStandardDate(Instant.now()));
209         Assertions.assertTrue(policy.isResponseCacheable("GET", response));
210     }
211 
212     @Test
213     public void testNon206WithMaxAgeIsCacheable() {
214         final int status = getRandomStatus();
215         response.setCode(status);
216         response.setHeader("Cache-Control", "max-age=0");
217         Assertions.assertTrue(policy.isResponseCacheable("GET", response));
218     }
219 
220     @Test
221     public void testNon206WithSMaxAgeIsCacheable() {
222         final int status = getRandomStatus();
223         response.setCode(status);
224         response.setHeader("Cache-Control", "s-maxage=0");
225         Assertions.assertTrue(policy.isResponseCacheable("GET", response));
226     }
227 
228     @Test
229     public void testNon206WithMustRevalidateIsCacheable() {
230         final int status = getRandomStatus();
231         response.setCode(status);
232         response.setHeader("Cache-Control", "must-revalidate");
233         Assertions.assertTrue(policy.isResponseCacheable("GET", response));
234     }
235 
236     @Test
237     public void testNon206WithProxyRevalidateIsCacheable() {
238         final int status = getRandomStatus();
239         response.setCode(status);
240         response.setHeader("Cache-Control", "proxy-revalidate");
241         Assertions.assertTrue(policy.isResponseCacheable("GET", response));
242     }
243 
244     @Test
245     public void testNon206WithPublicCacheControlIsCacheable() {
246         final int status = getRandomStatus();
247         response.setCode(status);
248         response.setHeader("Cache-Control", "public");
249         Assertions.assertTrue(policy.isResponseCacheable("GET", response));
250     }
251 
252     @Test
253     public void testNon206WithPrivateCacheControlIsNotCacheableBySharedCache() {
254         final int status = getRandomStatus();
255         response.setCode(status);
256         response.setHeader("Cache-Control", "private");
257         Assertions.assertFalse(policy.isResponseCacheable("GET", response));
258     }
259 
260     @Test
261     public void test200ResponseWithPrivateCacheControlIsCacheableByNonSharedCache() {
262         policy = new ResponseCachingPolicy(0, false, false, false);
263         response.setCode(HttpStatus.SC_OK);
264         response.setHeader("Cache-Control", "private");
265         Assertions.assertTrue(policy.isResponseCacheable("GET", response));
266     }
267 
268     @Test
269     public void testIsGetWithNoCacheCacheable() {
270         response.addHeader("Cache-Control", "no-cache");
271 
272         Assertions.assertFalse(policy.isResponseCacheable("GET", response));
273     }
274 
275     @Test
276     public void testIsHeadWithNoCacheCacheable() {
277         response.addHeader("Cache-Control", "no-cache");
278 
279         Assertions.assertFalse(policy.isResponseCacheable("HEAD", response));
280     }
281 
282     @Test
283     public void testIsGetWithNoStoreCacheable() {
284         response.addHeader("Cache-Control", "no-store");
285 
286         Assertions.assertFalse(policy.isResponseCacheable("GET", response));
287     }
288 
289     @Test
290     public void testIsHeadWithNoStoreCacheable() {
291         response.addHeader("Cache-Control", "no-store");
292 
293         Assertions.assertFalse(policy.isResponseCacheable("HEAD", response));
294     }
295 
296     @Test
297     public void testIsGetWithNoStoreEmbeddedInListCacheable() {
298         response.addHeader("Cache-Control", "public, no-store");
299 
300         Assertions.assertFalse(policy.isResponseCacheable("GET", response));
301     }
302 
303     @Test
304     public void testIsHeadWithNoStoreEmbeddedInListCacheable() {
305         response.addHeader("Cache-Control", "public, no-store");
306 
307         Assertions.assertFalse(policy.isResponseCacheable("HEAD", response));
308     }
309 
310     @Test
311     public void testIsGetWithNoCacheEmbeddedInListCacheable() {
312         response.addHeader("Cache-Control", "public, no-cache");
313 
314         Assertions.assertFalse(policy.isResponseCacheable("GET", response));
315     }
316 
317     @Test
318     public void testIsHeadWithNoCacheEmbeddedInListCacheable() {
319         response.addHeader("Cache-Control", "public, no-cache");
320 
321         Assertions.assertFalse(policy.isResponseCacheable("HEAD", response));
322     }
323 
324     @Test
325     public void testIsGetWithNoCacheEmbeddedInListAfterFirstHeaderCacheable() {
326         response.addHeader("Cache-Control", "max-age=20");
327         response.addHeader("Cache-Control", "public, no-cache");
328 
329         Assertions.assertFalse(policy.isResponseCacheable("GET", response));
330     }
331 
332     @Test
333     public void testIsHeadWithNoCacheEmbeddedInListAfterFirstHeaderCacheable() {
334         response.addHeader("Cache-Control", "max-age=20");
335         response.addHeader("Cache-Control", "public, no-cache");
336 
337         Assertions.assertFalse(policy.isResponseCacheable("HEAD", response));
338     }
339 
340     @Test
341     public void testIsGetWithNoStoreEmbeddedInListAfterFirstHeaderCacheable() {
342         response.addHeader("Cache-Control", "max-age=20");
343         response.addHeader("Cache-Control", "public, no-store");
344 
345         Assertions.assertFalse(policy.isResponseCacheable("GET", response));
346     }
347 
348     @Test
349     public void testIsHeadWithNoStoreEmbeddedInListAfterFirstHeaderCacheable() {
350         response.addHeader("Cache-Control", "max-age=20");
351         response.addHeader("Cache-Control", "public, no-store");
352 
353         Assertions.assertFalse(policy.isResponseCacheable("HEAD", response));
354     }
355 
356     @Test
357     public void testIsGetWithAnyCacheControlCacheable() {
358         response.addHeader("Cache-Control", "max=10");
359 
360         Assertions.assertTrue(policy.isResponseCacheable("GET", response));
361 
362         response = new BasicHttpResponse(HttpStatus.SC_OK, "");
363         response.setHeader("Date", DateUtils.formatStandardDate(Instant.now()));
364         response.addHeader("Cache-Control", "no-transform");
365         response.setHeader("Content-Length", "0");
366 
367         Assertions.assertTrue(policy.isResponseCacheable("GET", response));
368     }
369 
370     @Test
371     public void testIsHeadWithAnyCacheControlCacheable() {
372         policy = new ResponseCachingPolicy(0, true, false, false);
373         response.addHeader("Cache-Control", "max=10");
374 
375         Assertions.assertTrue(policy.isResponseCacheable("HEAD", response));
376 
377         response = new BasicHttpResponse(HttpStatus.SC_OK, "");
378         response.setHeader("Date", DateUtils.formatStandardDate(Instant.now()));
379         response.addHeader("Cache-Control", "no-transform");
380         response.setHeader("Content-Length", "0");
381 
382         Assertions.assertTrue(policy.isResponseCacheable("HEAD", response));
383     }
384 
385     @Test
386     public void testIsGetWithout200Cacheable() {
387         HttpResponse response404 = new BasicHttpResponse(HttpStatus.SC_NOT_FOUND, "");
388 
389         Assertions.assertFalse(policy.isResponseCacheable("GET", response404));
390 
391         response404 = new BasicHttpResponse(HttpStatus.SC_GATEWAY_TIMEOUT, "");
392 
393         Assertions.assertFalse(policy.isResponseCacheable("GET", response404));
394     }
395 
396     @Test
397     public void testIsHeadWithout200Cacheable() {
398         HttpResponse response404 = new BasicHttpResponse(HttpStatus.SC_NOT_FOUND, "");
399 
400         Assertions.assertFalse(policy.isResponseCacheable("HEAD", response404));
401 
402         response404 = new BasicHttpResponse(HttpStatus.SC_GATEWAY_TIMEOUT, "");
403 
404         Assertions.assertFalse(policy.isResponseCacheable("HEAD", response404));
405     }
406 
407     @Test
408     public void testVaryStarIsNotCacheable() {
409         response.setHeader("Vary", "*");
410         Assertions.assertFalse(policy.isResponseCacheable("GET", response));
411     }
412 
413     @Test
414     public void testVaryStarIsNotCacheableUsingSharedPublicCache() {
415         policy = new ResponseCachingPolicy(0, true, false, false);
416 
417         request.setHeader("Authorization", StandardAuthScheme.BASIC + " QWxhZGRpbjpvcGVuIHNlc2FtZQ==");
418         response.setHeader("Cache-Control", "public");
419         response.setHeader("Vary", "*");
420         Assertions.assertFalse(policy.isResponseCacheable(request, response));
421     }
422 
423     @Test
424     public void testIsGetWithVaryHeaderCacheable() {
425         response.addHeader("Vary", "Accept-Encoding");
426         Assertions.assertTrue(policy.isResponseCacheable("GET", response));
427     }
428 
429     @Test
430     public void testIsHeadWithVaryHeaderCacheable() {
431         policy = new ResponseCachingPolicy(0, true, false, false);
432         response.addHeader("Vary", "Accept-Encoding");
433         Assertions.assertTrue(policy.isResponseCacheable("HEAD", response));
434     }
435 
436     @Test
437     public void testIsArbitraryMethodCacheable() {
438 
439         Assertions.assertFalse(policy.isResponseCacheable("PUT", response));
440 
441         Assertions.assertFalse(policy.isResponseCacheable("get", response));
442     }
443 
444     @Test
445     public void testIsArbitraryMethodCacheableUsingSharedPublicCache() {
446         policy = new ResponseCachingPolicy(0, true, false, false);
447 
448         request = new HttpOptions("http://foo.example.com/");
449         request.setHeader("Authorization", StandardAuthScheme.BASIC + " QWxhZGRpbjpvcGVuIHNlc2FtZQ==");
450         response.setCode(HttpStatus.SC_NO_CONTENT);
451         response.setHeader("Cache-Control", "public");
452 
453         Assertions.assertFalse(policy.isResponseCacheable(request, response));
454     }
455 
456     @Test
457     public void testResponsesToRequestsWithNoStoreAreNotCacheable() {
458         request.setHeader("Cache-Control","no-store");
459         response.setHeader("Cache-Control","public");
460         Assertions.assertFalse(policy.isResponseCacheable(request,response));
461     }
462 
463     @Test
464     public void testResponsesWithMultipleAgeHeadersAreNotCacheable() {
465         response.addHeader("Age", "3");
466         response.addHeader("Age", "5");
467         Assertions.assertFalse(policy.isResponseCacheable("GET", response));
468     }
469 
470     @Test
471     public void testResponsesWithMultipleAgeHeadersAreNotCacheableUsingSharedPublicCache() {
472         policy = new ResponseCachingPolicy(0, true, false, false);
473 
474         request.setHeader("Authorization", StandardAuthScheme.BASIC + " QWxhZGRpbjpvcGVuIHNlc2FtZQ==");
475         response.setHeader("Cache-Control", "public");
476         response.addHeader("Age", "3");
477         response.addHeader("Age", "5");
478         Assertions.assertFalse(policy.isResponseCacheable(request, response));
479     }
480 
481     @Test
482     public void testResponsesWithMultipleDateHeadersAreNotCacheable() {
483         response.addHeader("Date", DateUtils.formatStandardDate(now));
484         response.addHeader("Date", DateUtils.formatStandardDate(sixSecondsAgo));
485         Assertions.assertFalse(policy.isResponseCacheable("GET", response));
486     }
487 
488     @Test
489     public void testResponsesWithMultipleDateHeadersAreNotCacheableUsingSharedPublicCache() {
490         policy = new ResponseCachingPolicy(0, true, false, false);
491 
492         request.setHeader("Authorization", StandardAuthScheme.BASIC + " QWxhZGRpbjpvcGVuIHNlc2FtZQ==");
493         response.setHeader("Cache-Control", "public");
494         response.addHeader("Date", DateUtils.formatStandardDate(now));
495         response.addHeader("Date", DateUtils.formatStandardDate(sixSecondsAgo));
496         Assertions.assertFalse(policy.isResponseCacheable(request, response));
497     }
498 
499     @Test
500     public void testResponsesWithMalformedDateHeadersAreNotCacheable() {
501         response.addHeader("Date", "garbage");
502         Assertions.assertFalse(policy.isResponseCacheable("GET", response));
503     }
504 
505     @Test
506     public void testResponsesWithMalformedDateHeadersAreNotCacheableUsingSharedPublicCache() {
507         policy = new ResponseCachingPolicy(0, true, false, false);
508 
509         request.setHeader("Authorization", StandardAuthScheme.BASIC + " QWxhZGRpbjpvcGVuIHNlc2FtZQ==");
510         response.setHeader("Cache-Control", "public");
511         response.addHeader("Date", "garbage");
512         Assertions.assertFalse(policy.isResponseCacheable(request, response));
513     }
514 
515     @Test
516     public void testResponsesWithMultipleExpiresHeadersAreNotCacheable() {
517         response.addHeader("Expires", DateUtils.formatStandardDate(now));
518         response.addHeader("Expires", DateUtils.formatStandardDate(sixSecondsAgo));
519         Assertions.assertFalse(policy.isResponseCacheable("GET", response));
520     }
521 
522     @Test
523     public void testResponsesWithMultipleExpiresHeadersAreNotCacheableUsingSharedPublicCache() {
524         policy = new ResponseCachingPolicy(0, true, false, false);
525 
526         request.setHeader("Authorization", StandardAuthScheme.BASIC + " QWxhZGRpbjpvcGVuIHNlc2FtZQ==");
527         response.setHeader("Cache-Control", "public");
528         response.addHeader("Expires", DateUtils.formatStandardDate(now));
529         response.addHeader("Expires", DateUtils.formatStandardDate(sixSecondsAgo));
530         Assertions.assertFalse(policy.isResponseCacheable(request, response));
531     }
532 
533     @Test
534     public void testResponsesWithoutDateHeadersAreNotCacheable() {
535         response.removeHeaders("Date");
536         Assertions.assertFalse(policy.isResponseCacheable("GET", response));
537     }
538 
539     @Test
540     public void testResponseThatHasTooMuchContentIsNotCacheable() {
541         response.setHeader("Content-Length", "9000");
542         Assertions.assertFalse(policy.isResponseCacheable("GET", response));
543     }
544 
545     @Test
546     public void testResponseThatHasTooMuchContentIsNotCacheableUsingSharedPublicCache() {
547         policy = new ResponseCachingPolicy(0, true, false, false);
548 
549         request.setHeader("Authorization", StandardAuthScheme.BASIC + " QWxhZGRpbjpvcGVuIHNlc2FtZQ==");
550         response.setHeader("Cache-Control", "public");
551         response.setHeader("Content-Length", "9000");
552         Assertions.assertFalse(policy.isResponseCacheable(request, response));
553     }
554 
555     @Test
556     public void testResponsesThatAreSmallEnoughAreCacheable() {
557         response.setHeader("Content-Length", "0");
558         Assertions.assertTrue(policy.isResponseCacheable("GET", response));
559     }
560 
561     @Test
562     public void testResponsesToGETWithQueryParamsButNoExplicitCachingAreNotCacheable() {
563         request = new BasicHttpRequest("GET", "/foo?s=bar");
564         Assertions.assertFalse(policy.isResponseCacheable(request, response));
565     }
566 
567     @Test
568     public void testResponsesToHEADWithQueryParamsButNoExplicitCachingAreNotCacheable() {
569         request = new BasicHttpRequest("HEAD", "/foo?s=bar");
570         Assertions.assertFalse(policy.isResponseCacheable(request, response));
571     }
572 
573     @Test
574     public void testResponsesToGETWithQueryParamsButNoExplicitCachingAreNotCacheableEvenWhen1_0QueryCachingDisabled() {
575         policy = new ResponseCachingPolicy(0, true, true, false);
576         request = new BasicHttpRequest("GET", "/foo?s=bar");
577         Assertions.assertFalse(policy.isResponseCacheable(request, response));
578     }
579 
580     @Test
581     public void testResponsesToHEADWithQueryParamsButNoExplicitCachingAreNotCacheableEvenWhen1_0QueryCachingDisabled() {
582         policy = new ResponseCachingPolicy(0, true, true, false);
583         request = new BasicHttpRequest("HEAD", "/foo?s=bar");
584         Assertions.assertFalse(policy.isResponseCacheable(request, response));
585     }
586 
587     @Test
588     public void testResponsesToGETWithQueryParamsAndExplicitCachingAreCacheable() {
589         request = new BasicHttpRequest("GET", "/foo?s=bar");
590         response.setHeader("Date", DateUtils.formatStandardDate(now));
591         response.setHeader("Expires", DateUtils.formatStandardDate(tenSecondsFromNow));
592         Assertions.assertTrue(policy.isResponseCacheable(request, response));
593     }
594 
595     @Test
596     public void testResponsesToHEADWithQueryParamsAndExplicitCachingAreCacheable() {
597         policy = new ResponseCachingPolicy(0, true, false, false);
598         request = new BasicHttpRequest("HEAD", "/foo?s=bar");
599         response.setHeader("Date", DateUtils.formatStandardDate(now));
600         response.setHeader("Expires", DateUtils.formatStandardDate(tenSecondsFromNow));
601         Assertions.assertTrue(policy.isResponseCacheable(request, response));
602     }
603 
604     @Test
605     public void testResponsesToGETWithQueryParamsAndExplicitCachingAreCacheableEvenWhen1_0QueryCachingDisabled() {
606         policy = new ResponseCachingPolicy(0, true, true, false);
607         request = new BasicHttpRequest("GET", "/foo?s=bar");
608         response.setHeader("Date", DateUtils.formatStandardDate(now));
609         response.setHeader("Expires", DateUtils.formatStandardDate(tenSecondsFromNow));
610         Assertions.assertTrue(policy.isResponseCacheable(request, response));
611     }
612 
613     @Test
614     public void testResponsesToHEADWithQueryParamsAndExplicitCachingAreCacheableEvenWhen1_0QueryCachingDisabled() {
615         policy = new ResponseCachingPolicy(0, true, true, false);
616         request = new BasicHttpRequest("HEAD", "/foo?s=bar");
617         response.setHeader("Date", DateUtils.formatStandardDate(now));
618         response.setHeader("Expires", DateUtils.formatStandardDate(tenSecondsFromNow));
619         Assertions.assertTrue(policy.isResponseCacheable(request, response));
620     }
621 
622     @Test
623     public void getsWithQueryParametersDirectlyFrom1_0OriginsAreNotCacheable() {
624         request = new BasicHttpRequest("GET", "/foo?s=bar");
625         response = new BasicHttpResponse(HttpStatus.SC_OK, "OK");
626         response.setVersion(HttpVersion.HTTP_1_0);
627         Assertions.assertFalse(policy.isResponseCacheable(request, response));
628     }
629 
630     @Test
631     public void headsWithQueryParametersDirectlyFrom1_0OriginsAreNotCacheable() {
632         request = new BasicHttpRequest("HEAD", "/foo?s=bar");
633         response = new BasicHttpResponse(HttpStatus.SC_OK, "OK");
634         response.setVersion(HttpVersion.HTTP_1_0);
635         Assertions.assertFalse(policy.isResponseCacheable(request, response));
636     }
637 
638     @Test
639     public void getsWithQueryParametersDirectlyFrom1_0OriginsAreNotCacheableEvenWithSetting() {
640         policy = new ResponseCachingPolicy(0, true, true, false);
641         request = new BasicHttpRequest("GET", "/foo?s=bar");
642         response = new BasicHttpResponse(HttpStatus.SC_OK, "OK");
643         response.setVersion(HttpVersion.HTTP_1_0);
644         Assertions.assertFalse(policy.isResponseCacheable(request, response));
645     }
646 
647     @Test
648     public void headsWithQueryParametersDirectlyFrom1_0OriginsAreNotCacheableEvenWithSetting() {
649         policy = new ResponseCachingPolicy(0, true, true, false);
650         request = new BasicHttpRequest("HEAD", "/foo?s=bar");
651         response = new BasicHttpResponse(HttpStatus.SC_OK, "OK");
652         response.setVersion(HttpVersion.HTTP_1_0);
653         Assertions.assertFalse(policy.isResponseCacheable(request, response));
654     }
655 
656     @Test
657     public void getsWithQueryParametersDirectlyFrom1_0OriginsAreCacheableWithExpires() {
658         request = new BasicHttpRequest("GET", "/foo?s=bar");
659         response = new BasicHttpResponse(HttpStatus.SC_OK, "OK");
660         response.setVersion(HttpVersion.HTTP_1_0);
661         response.setHeader("Date", DateUtils.formatStandardDate(now));
662         response.setHeader("Expires", DateUtils.formatStandardDate(tenSecondsFromNow));
663         Assertions.assertTrue(policy.isResponseCacheable(request, response));
664     }
665 
666     @Test
667     public void headsWithQueryParametersDirectlyFrom1_0OriginsAreCacheableWithExpires() {
668         policy = new ResponseCachingPolicy(0, true, false, false);
669         request = new BasicHttpRequest("HEAD", "/foo?s=bar");
670         response = new BasicHttpResponse(HttpStatus.SC_OK, "OK");
671         response.setVersion(HttpVersion.HTTP_1_0);
672         response.setHeader("Date", DateUtils.formatStandardDate(now));
673         response.setHeader("Expires", DateUtils.formatStandardDate(tenSecondsFromNow));
674         Assertions.assertTrue(policy.isResponseCacheable(request, response));
675     }
676 
677     @Test
678     public void getsWithQueryParametersDirectlyFrom1_0OriginsCanBeNotCacheableEvenWithExpires() {
679         policy = new ResponseCachingPolicy(0, true, true, false);
680         request = new BasicHttpRequest("GET", "/foo?s=bar");
681         response = new BasicHttpResponse(HttpStatus.SC_OK, "OK");
682         response.setVersion(HttpVersion.HTTP_1_0);
683         response.setHeader("Date", DateUtils.formatStandardDate(now));
684         response.setHeader("Expires", DateUtils.formatStandardDate(tenSecondsFromNow));
685         Assertions.assertFalse(policy.isResponseCacheable(request, response));
686     }
687 
688     @Test
689     public void headsWithQueryParametersDirectlyFrom1_0OriginsCanBeNotCacheableEvenWithExpires() {
690         policy = new ResponseCachingPolicy(0, true, true, false);
691         request = new BasicHttpRequest("HEAD", "/foo?s=bar");
692         response = new BasicHttpResponse(HttpStatus.SC_OK, "OK");
693         response.setVersion(HttpVersion.HTTP_1_0);
694         response.setHeader("Date", DateUtils.formatStandardDate(now));
695         response.setHeader("Expires", DateUtils.formatStandardDate(tenSecondsFromNow));
696         Assertions.assertFalse(policy.isResponseCacheable(request, response));
697     }
698 
699     @Test
700     public void getsWithQueryParametersFrom1_0OriginsViaProxiesAreNotCacheable() {
701         request = new BasicHttpRequest("GET", "/foo?s=bar");
702         response.setHeader("Via", "1.0 someproxy");
703         Assertions.assertFalse(policy.isResponseCacheable(request, response));
704     }
705 
706     @Test
707     public void headsWithQueryParametersFrom1_0OriginsViaProxiesAreNotCacheable() {
708         request = new BasicHttpRequest("HEAD", "/foo?s=bar");
709         response.setHeader("Via", "1.0 someproxy");
710         Assertions.assertFalse(policy.isResponseCacheable(request, response));
711     }
712 
713     @Test
714     public void getsWithQueryParametersFrom1_0OriginsViaProxiesAreCacheableWithExpires() {
715         request = new BasicHttpRequest("GET", "/foo?s=bar");
716         response.setHeader("Date", DateUtils.formatStandardDate(now));
717         response.setHeader("Expires", DateUtils.formatStandardDate(tenSecondsFromNow));
718         response.setHeader("Via", "1.0 someproxy");
719         Assertions.assertTrue(policy.isResponseCacheable(request, response));
720     }
721 
722     @Test
723     public void headsWithQueryParametersFrom1_0OriginsViaProxiesAreCacheableWithExpires() {
724         policy = new ResponseCachingPolicy(0, true, false, false);
725         request = new BasicHttpRequest("HEAD", "/foo?s=bar");
726         response.setHeader("Date", DateUtils.formatStandardDate(now));
727         response.setHeader("Expires", DateUtils.formatStandardDate(tenSecondsFromNow));
728         response.setHeader("Via", "1.0 someproxy");
729         Assertions.assertTrue(policy.isResponseCacheable(request, response));
730     }
731 
732     @Test
733     public void getsWithQueryParametersFrom1_0OriginsViaProxiesCanNotBeCacheableEvenWithExpires() {
734         policy = new ResponseCachingPolicy(0, true, true, true);
735         request = new BasicHttpRequest("GET", "/foo?s=bar");
736         response.setHeader("Date", DateUtils.formatStandardDate(now));
737         response.setHeader("Expires", DateUtils.formatStandardDate(tenSecondsFromNow));
738         response.setHeader("Via", "1.0 someproxy");
739         Assertions.assertFalse(policy.isResponseCacheable(request, response));
740     }
741 
742     @Test
743     public void headsWithQueryParametersFrom1_0OriginsViaProxiesCanNotBeCacheableEvenWithExpires() {
744         policy = new ResponseCachingPolicy(0, true, true, true);
745         request = new BasicHttpRequest("HEAD", "/foo?s=bar");
746         response.setHeader("Date", DateUtils.formatStandardDate(now));
747         response.setHeader("Expires", DateUtils.formatStandardDate(tenSecondsFromNow));
748         response.setHeader("Via", "1.0 someproxy");
749         Assertions.assertFalse(policy.isResponseCacheable(request, response));
750     }
751 
752     @Test
753     public void getsWithQueryParametersFrom1_0OriginsViaExplicitProxiesAreCacheableWithExpires() {
754         request = new BasicHttpRequest("GET", "/foo?s=bar");
755         response.setHeader("Date", DateUtils.formatStandardDate(now));
756         response.setHeader("Expires", DateUtils.formatStandardDate(tenSecondsFromNow));
757         response.setHeader("Via", "HTTP/1.0 someproxy");
758         Assertions.assertTrue(policy.isResponseCacheable(request, response));
759     }
760 
761     @Test
762     public void headsWithQueryParametersFrom1_0OriginsViaExplicitProxiesAreCacheableWithExpires() {
763         policy = new ResponseCachingPolicy(0, true, false, false);
764         request = new BasicHttpRequest("HEAD", "/foo?s=bar");
765         response.setHeader("Date", DateUtils.formatStandardDate(now));
766         response.setHeader("Expires", DateUtils.formatStandardDate(tenSecondsFromNow));
767         response.setHeader("Via", "HTTP/1.0 someproxy");
768         Assertions.assertTrue(policy.isResponseCacheable(request, response));
769     }
770 
771     @Test
772     public void getsWithQueryParametersFrom1_0OriginsViaExplicitProxiesCanNotBeCacheableEvenWithExpires() {
773         policy = new ResponseCachingPolicy(0, true, true, true);
774         request = new BasicHttpRequest("GET", "/foo?s=bar");
775         response.setHeader("Date", DateUtils.formatStandardDate(now));
776         response.setHeader("Expires", DateUtils.formatStandardDate(tenSecondsFromNow));
777         response.setHeader("Via", "HTTP/1.0 someproxy");
778         Assertions.assertFalse(policy.isResponseCacheable(request, response));
779     }
780 
781     @Test
782     public void headsWithQueryParametersFrom1_0OriginsViaExplicitProxiesCanNotBeCacheableEvenWithExpires() {
783         policy = new ResponseCachingPolicy(0, true, true, true);
784         request = new BasicHttpRequest("HEAD", "/foo?s=bar");
785         response.setHeader("Date", DateUtils.formatStandardDate(now));
786         response.setHeader("Expires", DateUtils.formatStandardDate(tenSecondsFromNow));
787         response.setHeader("Via", "HTTP/1.0 someproxy");
788         Assertions.assertFalse(policy.isResponseCacheable(request, response));
789     }
790 
791     @Test
792     public void getsWithQueryParametersFrom1_1OriginsVia1_0ProxiesAreCacheableWithExpires() {
793         request = new BasicHttpRequest("GET", "/foo?s=bar");
794         response = new BasicHttpResponse(HttpStatus.SC_OK, "OK");
795         response.setVersion(HttpVersion.HTTP_1_0);
796         response.setHeader("Date", DateUtils.formatStandardDate(now));
797         response.setHeader("Expires", DateUtils.formatStandardDate(tenSecondsFromNow));
798         response.setHeader("Via", "1.1 someproxy");
799         Assertions.assertTrue(policy.isResponseCacheable(request, response));
800     }
801 
802     @Test
803     public void headsWithQueryParametersFrom1_1OriginsVia1_0ProxiesAreCacheableWithExpires() {
804         policy = new ResponseCachingPolicy(0, true, false, false);
805         request = new BasicHttpRequest("HEAD", "/foo?s=bar");
806         response = new BasicHttpResponse(HttpStatus.SC_OK, "OK");
807         response.setVersion(HttpVersion.HTTP_1_0);
808         response.setHeader("Date", DateUtils.formatStandardDate(now));
809         response.setHeader("Expires", DateUtils.formatStandardDate(tenSecondsFromNow));
810         response.setHeader("Via", "1.1 someproxy");
811         Assertions.assertTrue(policy.isResponseCacheable(request, response));
812     }
813 
814     @Test
815     public void notCacheableIfExpiresEqualsDateAndNoCacheControl() {
816         response.setHeader("Date", DateUtils.formatStandardDate(now));
817         response.setHeader("Expires", DateUtils.formatStandardDate(now));
818         response.removeHeaders("Cache-Control");
819         Assertions.assertFalse(policy.isResponseCacheable(request, response));
820     }
821 
822     @Test
823     public void notCacheableIfExpiresPrecedesDateAndNoCacheControl() {
824         response.setHeader("Date", DateUtils.formatStandardDate(now));
825         response.setHeader("Expires", DateUtils.formatStandardDate(sixSecondsAgo));
826         response.removeHeaders("Cache-Control");
827         Assertions.assertFalse(policy.isResponseCacheable(request, response));
828     }
829 
830     @Test
831     public void test302WithExplicitCachingHeaders() {
832         response.setCode(HttpStatus.SC_MOVED_TEMPORARILY);
833         response.setHeader("Date", DateUtils.formatStandardDate(now));
834         response.setHeader("Cache-Control","max-age=300");
835         Assertions.assertTrue(policy.isResponseCacheable(request, response));
836     }
837 
838     @Test
839     public void test303WithExplicitCachingHeadersUnderDefaultBehavior() {
840         // RFC 2616 says: 303 should not be cached
841         response.setCode(HttpStatus.SC_SEE_OTHER);
842         response.setHeader("Date", DateUtils.formatStandardDate(now));
843         response.setHeader("Cache-Control","max-age=300");
844         Assertions.assertFalse(policy.isResponseCacheable(request, response));
845     }
846 
847     @Test
848     public void test303WithExplicitCachingHeadersWhenPermittedByConfig() {
849         // HTTPbis working group says ok if explicitly indicated by
850         // response headers
851         policy = new ResponseCachingPolicy(0, true, false, true);
852         response.setCode(HttpStatus.SC_SEE_OTHER);
853         response.setHeader("Date", DateUtils.formatStandardDate(now));
854         response.setHeader("Cache-Control","max-age=300");
855         Assertions.assertTrue(policy.isResponseCacheable(request, response));
856     }
857 
858     @Test
859     public void test307WithExplicitCachingHeaders() {
860         response.setCode(HttpStatus.SC_TEMPORARY_REDIRECT);
861         response.setHeader("Date", DateUtils.formatStandardDate(now));
862         response.setHeader("Cache-Control","max-age=300");
863         Assertions.assertTrue(policy.isResponseCacheable(request, response));
864     }
865 
866     @Test
867     public void otherStatusCodesAreCacheableWithExplicitCachingHeaders() {
868         response.setCode(HttpStatus.SC_NOT_FOUND);
869         response.setHeader("Date", DateUtils.formatStandardDate(now));
870         response.setHeader("Cache-Control","max-age=300");
871         Assertions.assertTrue(policy.isResponseCacheable(request, response));
872     }
873 
874     private int getRandomStatus() {
875         final int rnd = new Random().nextInt(acceptableCodes.length);
876 
877         return acceptableCodes[rnd];
878     }
879 }