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 static org.junit.jupiter.api.Assertions.assertFalse;
30  import static org.junit.jupiter.api.Assertions.assertTrue;
31  
32  import java.time.Duration;
33  import java.time.Instant;
34  import java.time.temporal.ChronoUnit;
35  import java.util.Random;
36  
37  import org.apache.hc.client5.http.auth.StandardAuthScheme;
38  import org.apache.hc.client5.http.cache.ResponseCacheControl;
39  import org.apache.hc.client5.http.classic.methods.HttpOptions;
40  import org.apache.hc.client5.http.utils.DateUtils;
41  import org.apache.hc.core5.http.HttpHeaders;
42  import org.apache.hc.core5.http.HttpRequest;
43  import org.apache.hc.core5.http.HttpResponse;
44  import org.apache.hc.core5.http.HttpStatus;
45  import org.apache.hc.core5.http.HttpVersion;
46  import org.apache.hc.core5.http.Method;
47  import org.apache.hc.core5.http.message.BasicHttpRequest;
48  import org.apache.hc.core5.http.message.BasicHttpResponse;
49  import org.junit.jupiter.api.Assertions;
50  import org.junit.jupiter.api.BeforeEach;
51  import org.junit.jupiter.api.Test;
52  
53  public class TestResponseCachingPolicy {
54  
55      private ResponseCachingPolicy policy;
56      private HttpResponse response;
57      private HttpRequest request;
58      private final int[] acceptableCodes = new int[] { HttpStatus.SC_OK,
59              HttpStatus.SC_NON_AUTHORITATIVE_INFORMATION, HttpStatus.SC_MULTIPLE_CHOICES,
60              HttpStatus.SC_MOVED_PERMANENTLY, HttpStatus.SC_GONE };
61      private Instant now;
62      private Instant tenSecondsFromNow;
63      private Instant sixSecondsAgo;
64      private ResponseCacheControl responseCacheControl;
65  
66      @BeforeEach
67      public void setUp() throws Exception {
68          now = Instant.now();
69          sixSecondsAgo = now.minusSeconds(6);
70          tenSecondsFromNow = now.plusSeconds(10);
71  
72          policy = new ResponseCachingPolicy(true, false, false);
73          request = new BasicHttpRequest("GET","/");
74          response = new BasicHttpResponse(HttpStatus.SC_OK, "");
75          response.setHeader("Date", DateUtils.formatStandardDate(Instant.now()));
76          response.setHeader("Content-Length", "0");
77          responseCacheControl = ResponseCacheControl.builder().build();
78      }
79  
80      @Test
81      public void testGetCacheable() {
82          policy = new ResponseCachingPolicy(true, false, false);
83          request = new BasicHttpRequest(Method.GET, "/");
84          Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
85      }
86  
87      @Test
88      public void testHeadCacheable() {
89          policy = new ResponseCachingPolicy(true, false, false);
90          request = new BasicHttpRequest(Method.HEAD, "/");
91          Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
92      }
93  
94      @Test
95      public void testArbitraryMethodNotCacheable() {
96          request = new BasicHttpRequest("PUT", "/");
97          Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
98  
99          request = new BasicHttpRequest("huh", "/");
100         Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
101     }
102 
103     @Test
104     public void testResponsesToRequestsWithAuthorizationHeadersAreNotCacheableBySharedCache() {
105         request = new BasicHttpRequest("GET","/");
106         request.setHeader("Authorization", StandardAuthScheme.BASIC + " dXNlcjpwYXNzd2Q=");
107         Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
108     }
109 
110     @Test
111     public void testResponsesToRequestsWithAuthorizationHeadersAreCacheableByNonSharedCache() {
112         policy = new ResponseCachingPolicy(false, false, false);
113         request = new BasicHttpRequest("GET","/");
114         request.setHeader("Authorization", StandardAuthScheme.BASIC + " dXNlcjpwYXNzd2Q=");
115         Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
116     }
117 
118     @Test
119     public void testAuthorizedResponsesWithSMaxAgeAreCacheable() {
120         request = new BasicHttpRequest("GET","/");
121         request.setHeader("Authorization", StandardAuthScheme.BASIC + " dXNlcjpwYXNzd2Q=");
122         responseCacheControl = ResponseCacheControl.builder()
123                 .setSharedMaxAge(3600)
124                 .build();
125 
126         Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
127     }
128 
129     @Test
130     public void testAuthorizedResponsesWithCacheControlPublicAreCacheable() {
131         request = new BasicHttpRequest("GET","/");
132         request.setHeader("Authorization", StandardAuthScheme.BASIC + " dXNlcjpwYXNzd2Q=");
133         responseCacheControl = ResponseCacheControl.builder()
134                 .setCachePublic(true)
135                 .build();
136         Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
137     }
138 
139     @Test
140     public void testAuthorizedResponsesWithCacheControlMaxAgeAreNotCacheable() {
141         request = new BasicHttpRequest("GET","/");
142         request.setHeader("Authorization", StandardAuthScheme.BASIC + " dXNlcjpwYXNzd2Q=");
143         responseCacheControl = ResponseCacheControl.builder()
144                 .setMaxAge(3600)
145                 .build();
146         Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
147     }
148 
149     @Test
150     public void test203ResponseCodeIsCacheable() {
151         response.setCode(HttpStatus.SC_NON_AUTHORITATIVE_INFORMATION);
152         Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
153     }
154 
155     @Test
156     public void test206ResponseCodeIsNotCacheable() {
157         response.setCode(HttpStatus.SC_PARTIAL_CONTENT);
158         Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
159     }
160 
161     @Test
162     public void test300ResponseCodeIsCacheable() {
163         response.setCode(HttpStatus.SC_MULTIPLE_CHOICES);
164         Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
165     }
166 
167     @Test
168     public void test301ResponseCodeIsCacheable() {
169         response.setCode(HttpStatus.SC_MOVED_PERMANENTLY);
170         Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
171     }
172 
173     @Test
174     public void test410ResponseCodeIsCacheable() {
175         response.setCode(HttpStatus.SC_GONE);
176         Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
177     }
178 
179     @Test
180     public void testPlain302ResponseCodeIsNotCacheable() {
181         response.setCode(HttpStatus.SC_MOVED_TEMPORARILY);
182         response.removeHeaders("Expires");
183         Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
184     }
185 
186     @Test
187     public void testPlain303ResponseCodeIsNotCacheableUnderDefaultBehavior() {
188         response.setCode(HttpStatus.SC_SEE_OTHER);
189         response.removeHeaders("Expires");
190         Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
191     }
192 
193     @Test
194     public void testPlain303ResponseCodeIsNotCacheableEvenIf303CachingEnabled() {
195         policy = new ResponseCachingPolicy(true, false, true);
196         response.setCode(HttpStatus.SC_SEE_OTHER);
197         response.removeHeaders("Expires");
198         Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
199     }
200 
201 
202     @Test
203     public void testPlain307ResponseCodeIsNotCacheable() {
204         response.setCode(HttpStatus.SC_TEMPORARY_REDIRECT);
205         response.removeHeaders("Expires");
206         Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
207     }
208 
209     @Test
210     public void testNon206WithExplicitExpiresIsCacheable() {
211         final int status = getRandomStatus();
212         response.setCode(status);
213         response.setHeader("Expires", DateUtils.formatStandardDate(Instant.now().plus(1, ChronoUnit.HOURS)));
214         Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
215     }
216 
217     @Test
218     public void testNon206WithMaxAgeIsCacheable() {
219         final int status = getRandomStatus();
220         response.setCode(status);
221         responseCacheControl = ResponseCacheControl.builder()
222                 .setMaxAge(0)
223                 .build();
224         Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
225     }
226 
227     @Test
228     public void testMissingCacheControlHeader() {
229         final int status = getRandomStatus();
230         response.setCode(status);
231         response.removeHeaders(HttpHeaders.CACHE_CONTROL);
232         Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
233     }
234 
235     @Test
236     public void testNon206WithSMaxAgeIsCacheable() {
237         final int status = getRandomStatus();
238         response.setCode(status);
239         responseCacheControl = ResponseCacheControl.builder()
240                 .setSharedMaxAge(1)
241                 .build();
242         Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
243     }
244 
245     @Test
246     public void testNon206WithMustRevalidateIsCacheable() {
247         final int status = getRandomStatus();
248         response.setCode(status);
249         responseCacheControl = ResponseCacheControl.builder()
250                 .setMustRevalidate(true)
251                 .build();
252         Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
253     }
254 
255     @Test
256     public void testNon206WithProxyRevalidateIsCacheable() {
257         final int status = getRandomStatus();
258         response.setCode(status);
259         responseCacheControl = ResponseCacheControl.builder()
260                 .setProxyRevalidate(true)
261                 .build();
262         Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
263     }
264 
265     @Test
266     public void testNon206WithPublicCacheControlIsCacheable() {
267         final int status = getRandomStatus();
268         response.setCode(status);
269         responseCacheControl = ResponseCacheControl.builder()
270                 .setCachePublic(true)
271                 .build();
272         Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
273     }
274 
275     @Test
276     public void testNon206WithPrivateCacheControlIsNotCacheableBySharedCache() {
277         final int status = getRandomStatus();
278         response.setCode(status);
279         responseCacheControl = ResponseCacheControl.builder()
280                 .setCachePrivate(true)
281                 .build();
282         Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
283     }
284 
285     @Test
286     public void test200ResponseWithPrivateCacheControlIsCacheableByNonSharedCache() {
287         policy = new ResponseCachingPolicy(false, false, false);
288         response.setCode(HttpStatus.SC_OK);
289         responseCacheControl = ResponseCacheControl.builder()
290                 .setCachePrivate(true)
291                 .build();
292         Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
293     }
294 
295     @Test
296     public void testControlNoCacheCacheable() {
297         responseCacheControl = ResponseCacheControl.builder()
298                 .setNoCache(true)
299                 .build();
300 
301         Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
302     }
303 
304     @Test
305     public void testControlNoStoreNotCacheable() {
306         responseCacheControl = ResponseCacheControl.builder()
307                 .setNoStore(true)
308                 .build();
309 
310         Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
311     }
312 
313     @Test
314     public void testControlNoStoreEmbeddedInListCacheable() {
315         responseCacheControl = ResponseCacheControl.builder()
316                 .setCachePublic(true)
317                 .setNoStore(true)
318                 .build();
319 
320         Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
321     }
322 
323     @Test
324     public void testControlNoCacheEmbeddedInListCacheable() {
325         responseCacheControl = ResponseCacheControl.builder()
326                 .setCachePublic(true)
327                 .setNoCache(true)
328                 .build();
329 
330         Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
331     }
332 
333     @Test
334     public void testControlNoCacheEmbeddedInListAfterFirstHeaderCacheable() {
335         responseCacheControl = ResponseCacheControl.builder()
336                 .setMaxAge(20)
337                 .setCachePublic(true)
338                 .setNoCache(true)
339                 .build();
340 
341         Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
342     }
343 
344     @Test
345     public void testControlNoStoreEmbeddedInListAfterFirstHeaderCacheable() {
346         responseCacheControl = ResponseCacheControl.builder()
347                 .setMaxAge(20)
348                 .setCachePublic(true)
349                 .setNoStore(true)
350                 .build();
351 
352         Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
353     }
354 
355     @Test
356     public void testControlAnyCacheControlCacheable() {
357         responseCacheControl = ResponseCacheControl.builder()
358                 .setMaxAge(10)
359                 .build();
360 
361         Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
362 
363         response = new BasicHttpResponse(HttpStatus.SC_OK, "");
364         response.setHeader("Date", DateUtils.formatStandardDate(Instant.now()));
365         response.setHeader("Content-Length", "0");
366         responseCacheControl = ResponseCacheControl.builder()
367                 .build();
368 
369         Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
370     }
371 
372     @Test
373     public void testControlWithout200Cacheable() {
374         HttpResponse response404 = new BasicHttpResponse(HttpStatus.SC_NOT_FOUND, "");
375 
376         Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response404));
377 
378         response404 = new BasicHttpResponse(HttpStatus.SC_GATEWAY_TIMEOUT, "");
379 
380         Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response404));
381     }
382 
383     @Test
384     public void testVaryStarIsNotCacheable() {
385         response.setHeader("Vary", "*");
386         Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
387     }
388 
389     @Test
390     public void testVaryStarIsNotCacheableUsingSharedPublicCache() {
391         policy = new ResponseCachingPolicy(true, false, false);
392 
393         request.setHeader("Authorization", StandardAuthScheme.BASIC + " QWxhZGRpbjpvcGVuIHNlc2FtZQ==");
394         response.setHeader("Vary", "*");
395         responseCacheControl = ResponseCacheControl.builder()
396                 .setCachePublic(true)
397                 .build();
398         Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
399     }
400 
401     @Test
402     public void testRequestWithVaryHeaderCacheable() {
403         response.addHeader("Vary", "Accept-Encoding");
404         Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
405     }
406 
407     @Test
408     public void testIsArbitraryMethodCacheableUsingSharedPublicCache() {
409         policy = new ResponseCachingPolicy(true, false, false);
410 
411         request = new HttpOptions("http://foo.example.com/");
412         request.setHeader("Authorization", StandardAuthScheme.BASIC + " QWxhZGRpbjpvcGVuIHNlc2FtZQ==");
413         response.setCode(HttpStatus.SC_NO_CONTENT);
414         responseCacheControl = ResponseCacheControl.builder()
415                 .setCachePublic(true)
416                 .build();
417 
418         Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
419     }
420 
421     @Test
422     public void testResponsesWithMultipleAgeHeadersAreCacheable() {
423         response.addHeader("Age", "3");
424         response.addHeader("Age", "5");
425         Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
426     }
427 
428     @Test
429     public void testResponsesWithMultipleAgeHeadersAreNotCacheableUsingSharedPublicCache() {
430         policy = new ResponseCachingPolicy(true, false, false);
431 
432         request.setHeader("Authorization", StandardAuthScheme.BASIC + " QWxhZGRpbjpvcGVuIHNlc2FtZQ==");
433         response.addHeader("Age", "3");
434         response.addHeader("Age", "5");
435         responseCacheControl = ResponseCacheControl.builder()
436                 .setCachePublic(true)
437                 .build();
438         Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
439     }
440 
441     @Test
442     public void testResponsesWithMultipleDateHeadersAreNotCacheable() {
443         response.addHeader("Date", DateUtils.formatStandardDate(now));
444         response.addHeader("Date", DateUtils.formatStandardDate(sixSecondsAgo));
445         Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
446     }
447 
448     @Test
449     public void testResponsesWithMultipleDateHeadersAreNotCacheableUsingSharedPublicCache() {
450         policy = new ResponseCachingPolicy(true, false, false);
451 
452         request.setHeader("Authorization", StandardAuthScheme.BASIC + " QWxhZGRpbjpvcGVuIHNlc2FtZQ==");
453         response.addHeader("Date", DateUtils.formatStandardDate(now));
454         response.addHeader("Date", DateUtils.formatStandardDate(sixSecondsAgo));
455         responseCacheControl = ResponseCacheControl.builder()
456                 .setCachePublic(true)
457                 .build();
458         Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
459     }
460 
461     @Test
462     public void testResponsesWithMalformedDateHeadersAreNotCacheable() {
463         response.addHeader("Date", "garbage");
464         Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
465     }
466 
467     @Test
468     public void testResponsesWithMalformedDateHeadersAreNotCacheableUsingSharedPublicCache() {
469         policy = new ResponseCachingPolicy(true, false, false);
470 
471         request.setHeader("Authorization", StandardAuthScheme.BASIC + " QWxhZGRpbjpvcGVuIHNlc2FtZQ==");
472         response.addHeader("Date", "garbage");
473         responseCacheControl = ResponseCacheControl.builder()
474                 .setCachePublic(true)
475                 .build();
476         Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
477     }
478 
479     @Test
480     public void testResponsesWithMultipleExpiresHeadersAreNotCacheable() {
481         response.addHeader("Expires", DateUtils.formatStandardDate(now));
482         response.addHeader("Expires", DateUtils.formatStandardDate(sixSecondsAgo));
483         Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
484     }
485 
486     @Test
487     public void testResponsesWithMultipleExpiresHeadersAreNotCacheableUsingSharedPublicCache() {
488         policy = new ResponseCachingPolicy(true, false, false);
489 
490         request.setHeader("Authorization", StandardAuthScheme.BASIC + " QWxhZGRpbjpvcGVuIHNlc2FtZQ==");
491         response.addHeader("Expires", DateUtils.formatStandardDate(now));
492         response.addHeader("Expires", DateUtils.formatStandardDate(sixSecondsAgo));
493         responseCacheControl = ResponseCacheControl.builder()
494                 .setCachePublic(true)
495                 .build();
496         Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
497     }
498 
499     @Test
500     public void testResponsesThatAreSmallEnoughAreCacheable() {
501         response.setHeader("Content-Length", "0");
502         Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
503     }
504 
505     @Test
506     public void testResponsesToGETWithQueryParamsButNoExplicitCachingAreNotCacheable() {
507         request = new BasicHttpRequest("GET", "/foo?s=bar");
508         Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
509     }
510 
511     @Test
512     public void testResponsesToHEADWithQueryParamsButNoExplicitCachingAreNotCacheable() {
513         request = new BasicHttpRequest("HEAD", "/foo?s=bar");
514         Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
515     }
516 
517     @Test
518     public void testResponsesToGETWithQueryParamsButNoExplicitCachingAreNotCacheableEvenWhen1_0QueryCachingDisabled() {
519         policy = new ResponseCachingPolicy(true, true, false);
520         request = new BasicHttpRequest("GET", "/foo?s=bar");
521         Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
522     }
523 
524     @Test
525     public void testResponsesToHEADWithQueryParamsButNoExplicitCachingAreNotCacheableEvenWhen1_0QueryCachingDisabled() {
526         policy = new ResponseCachingPolicy(true, true, false);
527         request = new BasicHttpRequest("HEAD", "/foo?s=bar");
528         Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
529     }
530 
531     @Test
532     public void testResponsesToGETWithQueryParamsAndExplicitCachingAreCacheable() {
533         request = new BasicHttpRequest("GET", "/foo?s=bar");
534         response.setHeader("Date", DateUtils.formatStandardDate(now));
535         response.setHeader("Expires", DateUtils.formatStandardDate(tenSecondsFromNow));
536         Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
537     }
538 
539     @Test
540     public void testResponsesToHEADWithQueryParamsAndExplicitCachingAreCacheable() {
541         policy = new ResponseCachingPolicy(true, false, false);
542         request = new BasicHttpRequest("HEAD", "/foo?s=bar");
543         response.setHeader("Date", DateUtils.formatStandardDate(now));
544         response.setHeader("Expires", DateUtils.formatStandardDate(tenSecondsFromNow));
545         Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
546     }
547 
548     @Test
549     public void testResponsesToGETWithQueryParamsAndExplicitCachingAreCacheableEvenWhen1_0QueryCachingDisabled() {
550         policy = new ResponseCachingPolicy(true, true, false);
551         request = new BasicHttpRequest("GET", "/foo?s=bar");
552         response.setHeader("Date", DateUtils.formatStandardDate(now));
553         response.setHeader("Expires", DateUtils.formatStandardDate(tenSecondsFromNow));
554         Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
555     }
556 
557     @Test
558     public void testResponsesToHEADWithQueryParamsAndExplicitCachingAreCacheableEvenWhen1_0QueryCachingDisabled() {
559         policy = new ResponseCachingPolicy(true, true, false);
560         request = new BasicHttpRequest("HEAD", "/foo?s=bar");
561         response.setHeader("Date", DateUtils.formatStandardDate(now));
562         response.setHeader("Expires", DateUtils.formatStandardDate(tenSecondsFromNow));
563         Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
564     }
565 
566     @Test
567     public void getsWithQueryParametersDirectlyFrom1_0OriginsAreNotCacheable() {
568         request = new BasicHttpRequest("GET", "/foo?s=bar");
569         response = new BasicHttpResponse(HttpStatus.SC_OK, "OK");
570         response.setVersion(HttpVersion.HTTP_1_0);
571         Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
572     }
573 
574     @Test
575     public void headsWithQueryParametersDirectlyFrom1_0OriginsAreNotCacheable() {
576         request = new BasicHttpRequest("HEAD", "/foo?s=bar");
577         response = new BasicHttpResponse(HttpStatus.SC_OK, "OK");
578         response.setVersion(HttpVersion.HTTP_1_0);
579         Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
580     }
581 
582     @Test
583     public void getsWithQueryParametersDirectlyFrom1_0OriginsAreNotCacheableEvenWithSetting() {
584         policy = new ResponseCachingPolicy(true, true, false);
585         request = new BasicHttpRequest("GET", "/foo?s=bar");
586         response = new BasicHttpResponse(HttpStatus.SC_OK, "OK");
587         response.setVersion(HttpVersion.HTTP_1_0);
588         Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
589     }
590 
591     @Test
592     public void headsWithQueryParametersDirectlyFrom1_0OriginsAreNotCacheableEvenWithSetting() {
593         policy = new ResponseCachingPolicy(true, true, false);
594         request = new BasicHttpRequest("HEAD", "/foo?s=bar");
595         response = new BasicHttpResponse(HttpStatus.SC_OK, "OK");
596         response.setVersion(HttpVersion.HTTP_1_0);
597         Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
598     }
599 
600     @Test
601     public void getsWithQueryParametersDirectlyFrom1_0OriginsAreCacheableWithExpires() {
602         request = new BasicHttpRequest("GET", "/foo?s=bar");
603         response = new BasicHttpResponse(HttpStatus.SC_OK, "OK");
604         response.setVersion(HttpVersion.HTTP_1_0);
605         response.setHeader("Date", DateUtils.formatStandardDate(now));
606         response.setHeader("Expires", DateUtils.formatStandardDate(tenSecondsFromNow));
607         Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
608     }
609 
610     @Test
611     public void headsWithQueryParametersDirectlyFrom1_0OriginsAreCacheableWithExpires() {
612         policy = new ResponseCachingPolicy(true, false, false);
613         request = new BasicHttpRequest("HEAD", "/foo?s=bar");
614         response = new BasicHttpResponse(HttpStatus.SC_OK, "OK");
615         response.setVersion(HttpVersion.HTTP_1_0);
616         response.setHeader("Date", DateUtils.formatStandardDate(now));
617         response.setHeader("Expires", DateUtils.formatStandardDate(tenSecondsFromNow));
618         Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
619     }
620 
621     @Test
622     public void getsWithQueryParametersDirectlyFrom1_0OriginsCanBeNotCacheableEvenWithExpires() {
623         policy = new ResponseCachingPolicy(true, true, false);
624         request = new BasicHttpRequest("GET", "/foo?s=bar");
625         response = new BasicHttpResponse(HttpStatus.SC_OK, "OK");
626         response.setVersion(HttpVersion.HTTP_1_0);
627         response.setHeader("Date", DateUtils.formatStandardDate(now));
628         response.setHeader("Expires", DateUtils.formatStandardDate(tenSecondsFromNow));
629         Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
630     }
631 
632     @Test
633     public void headsWithQueryParametersDirectlyFrom1_0OriginsCanBeNotCacheableEvenWithExpires() {
634         policy = new ResponseCachingPolicy(true, true, false);
635         request = new BasicHttpRequest("HEAD", "/foo?s=bar");
636         response = new BasicHttpResponse(HttpStatus.SC_OK, "OK");
637         response.setVersion(HttpVersion.HTTP_1_0);
638         response.setHeader("Date", DateUtils.formatStandardDate(now));
639         response.setHeader("Expires", DateUtils.formatStandardDate(tenSecondsFromNow));
640         Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
641     }
642 
643     @Test
644     public void getsWithQueryParametersFrom1_0OriginsViaProxiesAreNotCacheable() {
645         request = new BasicHttpRequest("GET", "/foo?s=bar");
646         response.setHeader(HttpHeaders.VIA, "1.0 someproxy");
647         Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
648     }
649 
650     @Test
651     public void headsWithQueryParametersFrom1_0OriginsViaProxiesAreNotCacheable() {
652         request = new BasicHttpRequest("HEAD", "/foo?s=bar");
653         response.setHeader(HttpHeaders.VIA, "1.0 someproxy");
654         Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
655     }
656 
657     @Test
658     public void getsWithQueryParametersFrom1_0OriginsViaProxiesAreCacheableWithExpires() {
659         request = new BasicHttpRequest("GET", "/foo?s=bar");
660         response.setHeader("Date", DateUtils.formatStandardDate(now));
661         response.setHeader("Expires", DateUtils.formatStandardDate(tenSecondsFromNow));
662         response.setHeader(HttpHeaders.VIA, "1.0 someproxy");
663         Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
664     }
665 
666     @Test
667     public void headsWithQueryParametersFrom1_0OriginsViaProxiesAreCacheableWithExpires() {
668         policy = new ResponseCachingPolicy(true, false, false);
669         request = new BasicHttpRequest("HEAD", "/foo?s=bar");
670         response.setHeader("Date", DateUtils.formatStandardDate(now));
671         response.setHeader("Expires", DateUtils.formatStandardDate(tenSecondsFromNow));
672         response.setHeader(HttpHeaders.VIA, "1.0 someproxy");
673         Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
674     }
675 
676     @Test
677     public void getsWithQueryParametersFrom1_0OriginsViaProxiesCanNotBeCacheableEvenWithExpires() {
678         policy = new ResponseCachingPolicy(true, true, true);
679         request = new BasicHttpRequest("GET", "/foo?s=bar");
680         response.setHeader("Date", DateUtils.formatStandardDate(now));
681         response.setHeader("Expires", DateUtils.formatStandardDate(tenSecondsFromNow));
682         response.setHeader(HttpHeaders.VIA, "1.0 someproxy");
683         Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
684     }
685 
686     @Test
687     public void headsWithQueryParametersFrom1_0OriginsViaProxiesCanNotBeCacheableEvenWithExpires() {
688         policy = new ResponseCachingPolicy(true, true, true);
689         request = new BasicHttpRequest("HEAD", "/foo?s=bar");
690         response.setHeader("Date", DateUtils.formatStandardDate(now));
691         response.setHeader("Expires", DateUtils.formatStandardDate(tenSecondsFromNow));
692         response.setHeader(HttpHeaders.VIA, "1.0 someproxy");
693         Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
694     }
695 
696     @Test
697     public void getsWithQueryParametersFrom1_0OriginsViaExplicitProxiesAreCacheableWithExpires() {
698         request = new BasicHttpRequest("GET", "/foo?s=bar");
699         response.setHeader("Date", DateUtils.formatStandardDate(now));
700         response.setHeader("Expires", DateUtils.formatStandardDate(tenSecondsFromNow));
701         response.setHeader(HttpHeaders.VIA, "HTTP/1.0 someproxy");
702         Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
703     }
704 
705     @Test
706     public void headsWithQueryParametersFrom1_0OriginsViaExplicitProxiesAreCacheableWithExpires() {
707         policy = new ResponseCachingPolicy(true, false, false);
708         request = new BasicHttpRequest("HEAD", "/foo?s=bar");
709         response.setHeader("Date", DateUtils.formatStandardDate(now));
710         response.setHeader("Expires", DateUtils.formatStandardDate(tenSecondsFromNow));
711         response.setHeader(HttpHeaders.VIA, "HTTP/1.0 someproxy");
712         Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
713     }
714 
715     @Test
716     public void getsWithQueryParametersFrom1_0OriginsViaExplicitProxiesCanNotBeCacheableEvenWithExpires() {
717         policy = new ResponseCachingPolicy(true, true, true);
718         request = new BasicHttpRequest("GET", "/foo?s=bar");
719         response.setHeader("Date", DateUtils.formatStandardDate(now));
720         response.setHeader("Expires", DateUtils.formatStandardDate(tenSecondsFromNow));
721         response.setHeader(HttpHeaders.VIA, "HTTP/1.0 someproxy");
722         Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
723     }
724 
725     @Test
726     public void headsWithQueryParametersFrom1_0OriginsViaExplicitProxiesCanNotBeCacheableEvenWithExpires() {
727         policy = new ResponseCachingPolicy(true, true, true);
728         request = new BasicHttpRequest("HEAD", "/foo?s=bar");
729         response.setHeader("Date", DateUtils.formatStandardDate(now));
730         response.setHeader("Expires", DateUtils.formatStandardDate(tenSecondsFromNow));
731         response.setHeader(HttpHeaders.VIA, "HTTP/1.0 someproxy");
732         Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
733     }
734 
735     @Test
736     public void getsWithQueryParametersFrom1_1OriginsVia1_0ProxiesAreCacheableWithExpires() {
737         request = new BasicHttpRequest("GET", "/foo?s=bar");
738         response = new BasicHttpResponse(HttpStatus.SC_OK, "OK");
739         response.setVersion(HttpVersion.HTTP_1_0);
740         response.setHeader("Date", DateUtils.formatStandardDate(now));
741         response.setHeader("Expires", DateUtils.formatStandardDate(tenSecondsFromNow));
742         response.setHeader(HttpHeaders.VIA, "1.1 someproxy");
743         Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
744     }
745 
746     @Test
747     public void headsWithQueryParametersFrom1_1OriginsVia1_0ProxiesAreCacheableWithExpires() {
748         policy = new ResponseCachingPolicy(true, false, false);
749         request = new BasicHttpRequest("HEAD", "/foo?s=bar");
750         response = new BasicHttpResponse(HttpStatus.SC_OK, "OK");
751         response.setVersion(HttpVersion.HTTP_1_0);
752         response.setHeader("Date", DateUtils.formatStandardDate(now));
753         response.setHeader("Expires", DateUtils.formatStandardDate(tenSecondsFromNow));
754         response.setHeader(HttpHeaders.VIA, "1.1 someproxy");
755 
756         Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
757     }
758 
759     @Test
760     public void notCacheableIfExpiresEqualsDateAndNoCacheControl() {
761         response.setHeader("Date", DateUtils.formatStandardDate(now));
762         response.setHeader("Expires", DateUtils.formatStandardDate(now));
763         Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
764     }
765 
766     @Test
767     public void notCacheableIfExpiresPrecedesDateAndNoCacheControl() {
768         response.setHeader("Date", DateUtils.formatStandardDate(now));
769         response.setHeader("Expires", DateUtils.formatStandardDate(sixSecondsAgo));
770         Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
771     }
772 
773     @Test
774     public void test302WithExplicitCachingHeaders() {
775         response.setCode(HttpStatus.SC_MOVED_TEMPORARILY);
776         response.setHeader("Date", DateUtils.formatStandardDate(now));
777         responseCacheControl = ResponseCacheControl.builder()
778                 .setMaxAge(300)
779                 .build();
780         Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
781     }
782 
783     @Test
784     public void test303WithExplicitCachingHeadersWhenPermittedByConfig() {
785         // HTTPbis working group says ok if explicitly indicated by
786         // response headers
787         policy = new ResponseCachingPolicy(true, false, true);
788         response.setCode(HttpStatus.SC_SEE_OTHER);
789         response.setHeader("Date", DateUtils.formatStandardDate(now));
790         responseCacheControl = ResponseCacheControl.builder()
791                 .setMaxAge(300)
792                 .build();
793         Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
794     }
795 
796     @Test
797     public void test307WithExplicitCachingHeaders() {
798         response.setCode(HttpStatus.SC_TEMPORARY_REDIRECT);
799         response.setHeader("Date", DateUtils.formatStandardDate(now));
800         responseCacheControl = ResponseCacheControl.builder()
801                 .setMaxAge(300)
802                 .build();
803         Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
804     }
805 
806     @Test
807     public void otherStatusCodesAreCacheableWithExplicitCachingHeaders() {
808         response.setCode(HttpStatus.SC_NOT_FOUND);
809         response.setHeader("Date", DateUtils.formatStandardDate(now));
810         responseCacheControl = ResponseCacheControl.builder()
811                 .setMaxAge(300)
812                 .build();
813         assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
814     }
815 
816     @Test
817     void testIsResponseCacheableNullCacheControl() {
818 
819         // Set up test data
820         final Duration tenSecondsFromNow = Duration.ofSeconds(10);
821 
822         response = new BasicHttpResponse(HttpStatus.SC_OK, "");
823         response.setHeader(HttpHeaders.DATE, DateUtils.formatStandardDate(Instant.now()));
824         response.setHeader(HttpHeaders.EXPIRES, DateUtils.formatStandardDate(Instant.now().plus(tenSecondsFromNow)));
825 
826 
827         // Create ResponseCachingPolicy instance and test the method
828         policy = new ResponseCachingPolicy(true, false, false);
829         request = new BasicHttpRequest("GET", "/foo");
830         assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
831     }
832 
833 
834     @Test
835     void testIsResponseCacheableNotNullCacheControlSmaxAge60() {
836 
837         // Set up test data
838         final Duration tenSecondsFromNow = Duration.ofSeconds(10);
839 
840         response = new BasicHttpResponse(HttpStatus.SC_OK, "");
841         response.setHeader(HttpHeaders.DATE, DateUtils.formatStandardDate(Instant.now()));
842         response.setHeader(HttpHeaders.EXPIRES, DateUtils.formatStandardDate(Instant.now().plus(tenSecondsFromNow)));
843 
844 
845         // Create ResponseCachingPolicy instance and test the method
846         policy = new ResponseCachingPolicy(true, false, false);
847         request = new BasicHttpRequest("GET", "/foo");
848         responseCacheControl = ResponseCacheControl.builder()
849                 .setMaxAge(60)
850                 .build();
851         assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
852     }
853 
854     @Test
855     void testIsResponseCacheableNotNullCacheControlMaxAge60() {
856 
857         // Set up test data
858         final Duration tenSecondsFromNow = Duration.ofSeconds(10);
859 
860         response = new BasicHttpResponse(HttpStatus.SC_OK, "");
861         response.setHeader(HttpHeaders.DATE, DateUtils.formatStandardDate(Instant.now()));
862         response.setHeader(HttpHeaders.EXPIRES, DateUtils.formatStandardDate(Instant.now().plus(tenSecondsFromNow)));
863 
864 
865         // Create ResponseCachingPolicy instance and test the method
866         policy = new ResponseCachingPolicy(true, false, false);
867         request = new BasicHttpRequest("GET", "/foo");
868         responseCacheControl = ResponseCacheControl.builder()
869                 .setMaxAge(60)
870                 .build();
871         assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
872     }
873 
874     @Test
875     void testIsResponseCacheableNotExsiresAndDate() {
876 
877         // Set up test data
878         final Duration tenSecondsFromNow = Duration.ofSeconds(10);
879 
880         response = new BasicHttpResponse(HttpStatus.SC_OK, "");
881         response.setHeader(HttpHeaders.DATE, DateUtils.formatStandardDate(Instant.now()));
882         response.setHeader(HttpHeaders.EXPIRES, DateUtils.formatStandardDate(Instant.now().plus(tenSecondsFromNow)));
883 
884 
885         // Create ResponseCachingPolicy instance and test the method
886         policy = new ResponseCachingPolicy(true, false, false);
887         request = new BasicHttpRequest("GET", "/foo");
888         assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
889     }
890 
891     private int getRandomStatus() {
892         final int rnd = new Random().nextInt(acceptableCodes.length);
893 
894         return acceptableCodes[rnd];
895     }
896 
897     @Test
898     public void testIsResponseCacheable() {
899         request = new BasicHttpRequest("GET","/foo?s=bar");
900         // HTTPbis working group says ok if explicitly indicated by
901         // response headers
902         policy = new ResponseCachingPolicy(true, false, true);
903         response.setCode(HttpStatus.SC_OK);
904         response.setHeader("Date", DateUtils.formatStandardDate(now));
905         assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
906     }
907 
908     @Test
909     void testIsResponseCacheableNoCache() {
910         // Set up test data
911         response = new BasicHttpResponse(HttpStatus.SC_OK, "");
912         response.setHeader(HttpHeaders.DATE, DateUtils.formatStandardDate(Instant.now()));
913 
914         // Create ResponseCachingPolicy instance and test the method
915         policy = new ResponseCachingPolicy(true, false, false);
916         request = new BasicHttpRequest("GET", "/foo");
917         responseCacheControl = ResponseCacheControl.builder()
918                 .setNoCache(true)
919                 .build();
920         assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
921     }
922 
923     @Test
924     void testIsResponseCacheableNoStore() {
925         // Set up test data
926         response = new BasicHttpResponse(HttpStatus.SC_OK, "");
927         response.setHeader(HttpHeaders.DATE, DateUtils.formatStandardDate(Instant.now()));
928 
929         // Create ResponseCachingPolicy instance and test the method
930         policy = new ResponseCachingPolicy(true, false, false);
931         request = new BasicHttpRequest("GET", "/foo");
932         responseCacheControl = ResponseCacheControl.builder()
933                 .setNoStore(true)
934                 .build();
935         assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
936     }
937 
938     @Test
939     public void testImmutableAndFreshResponseIsCacheable() {
940         responseCacheControl = ResponseCacheControl.builder()
941                 .setImmutable(true)
942                 .setMaxAge(3600) // set this to a value that ensures the response is still fresh
943                 .build();
944 
945         Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
946     }
947 }