1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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 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 void setUp() {
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 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 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 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 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 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 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 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 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 void test203ResponseCodeIsCacheable() {
151 response.setCode(HttpStatus.SC_NON_AUTHORITATIVE_INFORMATION);
152 Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
153 }
154
155 @Test
156 void test206ResponseCodeIsNotCacheable() {
157 response.setCode(HttpStatus.SC_PARTIAL_CONTENT);
158 Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
159 }
160
161 @Test
162 void test300ResponseCodeIsCacheable() {
163 response.setCode(HttpStatus.SC_MULTIPLE_CHOICES);
164 Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
165 }
166
167 @Test
168 void test301ResponseCodeIsCacheable() {
169 response.setCode(HttpStatus.SC_MOVED_PERMANENTLY);
170 Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
171 }
172
173 @Test
174 void test410ResponseCodeIsCacheable() {
175 response.setCode(HttpStatus.SC_GONE);
176 Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
177 }
178
179 @Test
180 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 void testVaryStarIsNotCacheable() {
385 response.setHeader("Vary", "*");
386 Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
387 }
388
389 @Test
390 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 void testRequestWithVaryHeaderCacheable() {
403 response.addHeader("Vary", "Accept-Encoding");
404 Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
405 }
406
407 @Test
408 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 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 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 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 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 void testResponsesWithMalformedDateHeadersAreNotCacheable() {
463 response.addHeader("Date", "garbage");
464 Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
465 }
466
467 @Test
468 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 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 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 void testResponsesThatAreSmallEnoughAreCacheable() {
501 response.setHeader("Content-Length", "0");
502 Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
503 }
504
505 @Test
506 void testResponsesToGETWithQueryParamsButNoExplicitCachingAreNotCacheable() {
507 request = new BasicHttpRequest("GET", "/foo?s=bar");
508 Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
509 }
510
511 @Test
512 void testResponsesToHEADWithQueryParamsButNoExplicitCachingAreNotCacheable() {
513 request = new BasicHttpRequest("HEAD", "/foo?s=bar");
514 Assertions.assertFalse(policy.isResponseCacheable(responseCacheControl, request, response));
515 }
516
517 @Test
518 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 void test303WithExplicitCachingHeadersWhenPermittedByConfig() {
785
786
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 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 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
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
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
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
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
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
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
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
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 void testIsResponseCacheable() {
899 request = new BasicHttpRequest("GET","/foo?s=bar");
900
901
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
911 response = new BasicHttpResponse(HttpStatus.SC_OK, "");
912 response.setHeader(HttpHeaders.DATE, DateUtils.formatStandardDate(Instant.now()));
913
914
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
926 response = new BasicHttpResponse(HttpStatus.SC_OK, "");
927 response.setHeader(HttpHeaders.DATE, DateUtils.formatStandardDate(Instant.now()));
928
929
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 void testImmutableAndFreshResponseIsCacheable() {
940 responseCacheControl = ResponseCacheControl.builder()
941 .setImmutable(true)
942 .setMaxAge(3600)
943 .build();
944
945 Assertions.assertTrue(policy.isResponseCacheable(responseCacheControl, request, response));
946 }
947
948 @Test
949 void testPublicWithAuthorizationIsCacheable() {
950 request = new BasicHttpRequest("GET", "/resource");
951 request.setHeader(HttpHeaders.AUTHORIZATION, "Basic dXNlcjpwYXNzd2Q=");
952 response.setHeader("Cache-Control", "public");
953 responseCacheControl = ResponseCacheControl.builder()
954 .setCachePublic(true)
955 .build();
956
957 final boolean isCacheable = policy.isResponseCacheable(responseCacheControl, request, response);
958 Assertions.assertTrue(isCacheable,
959 "Response with public directive and Authorization header should be cacheable in shared cache.");
960 }
961
962 @Test
963 void testSMaxageWithAuthorizationIsCacheable() {
964 request = new BasicHttpRequest("GET", "/resource");
965 request.setHeader(HttpHeaders.AUTHORIZATION, "Basic dXNlcjpwYXNzd2Q=");
966 response.setHeader("Cache-Control", "s-maxage=60");
967 responseCacheControl = ResponseCacheControl.builder()
968 .setSharedMaxAge(60)
969 .build();
970
971 final boolean isCacheable = policy.isResponseCacheable(responseCacheControl, request, response);
972 Assertions.assertTrue(isCacheable,
973 "Response with s-maxage and Authorization header should be cacheable in shared cache.");
974 }
975
976 @Test
977 void testNoDirectivesWithAuthorizationNotCacheable() {
978 request = new BasicHttpRequest("GET", "/resource");
979 request.setHeader(HttpHeaders.AUTHORIZATION, "Basic dXNlcjpwYXNzd2Q=");
980 response.setHeader("Cache-Control", "");
981 responseCacheControl = ResponseCacheControl.builder()
982 .build();
983
984 final boolean isCacheable = policy.isResponseCacheable(responseCacheControl, request, response);
985 Assertions.assertFalse(isCacheable,
986 "Response without must-revalidate, public, or s-maxage should not be cacheable with Authorization header.");
987 }
988
989 @Test
990 void testMustRevalidateWithAuthorizationIsCacheable() {
991 request = new BasicHttpRequest("GET", "/resource");
992 request.setHeader(HttpHeaders.AUTHORIZATION, "Basic dXNlcjpwYXNzd2Q=");
993 response.setHeader("Cache-Control", "must-revalidate");
994 responseCacheControl = ResponseCacheControl.builder()
995 .setMustRevalidate(true)
996 .build();
997
998 final boolean isCacheable = policy.isResponseCacheable(responseCacheControl, request, response);
999 Assertions.assertTrue(isCacheable,
1000 "Response with must-revalidate and Authorization header should be cacheable in shared cache.");
1001 }
1002
1003 }