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 java.io.IOException;
30 import java.time.Instant;
31 import java.util.concurrent.atomic.AtomicLong;
32
33 import org.apache.hc.client5.http.async.methods.SimpleHttpResponse;
34 import org.apache.hc.client5.http.cache.HttpCacheEntry;
35 import org.apache.hc.client5.http.cache.ResourceIOException;
36 import org.apache.hc.core5.http.EntityDetails;
37 import org.apache.hc.core5.http.Header;
38 import org.apache.hc.core5.http.HttpHeaders;
39 import org.apache.hc.core5.http.HttpRequest;
40 import org.apache.hc.core5.http.HttpResponse;
41 import org.apache.hc.core5.http.HttpStatus;
42 import org.apache.hc.core5.http.Method;
43
44 public class CachingExecBase {
45
46 final AtomicLong cacheHits = new AtomicLong();
47 final AtomicLong cacheMisses = new AtomicLong();
48 final AtomicLong cacheUpdates = new AtomicLong();
49
50 final ResponseCachingPolicy responseCachingPolicy;
51 final CacheValidityPolicy validityPolicy;
52 final CachedHttpResponseGenerator responseGenerator;
53 final CacheableRequestPolicy cacheableRequestPolicy;
54 final CachedResponseSuitabilityChecker suitabilityChecker;
55 final CacheConfig cacheConfig;
56
57 CachingExecBase(
58 final CacheValidityPolicy validityPolicy,
59 final ResponseCachingPolicy responseCachingPolicy,
60 final CachedHttpResponseGenerator responseGenerator,
61 final CacheableRequestPolicy cacheableRequestPolicy,
62 final CachedResponseSuitabilityChecker suitabilityChecker,
63 final CacheConfig config) {
64 this.responseCachingPolicy = responseCachingPolicy;
65 this.validityPolicy = validityPolicy;
66 this.responseGenerator = responseGenerator;
67 this.cacheableRequestPolicy = cacheableRequestPolicy;
68 this.suitabilityChecker = suitabilityChecker;
69 this.cacheConfig = config != null ? config : CacheConfig.DEFAULT;
70 }
71
72 CachingExecBase(final CacheConfig config) {
73 super();
74 this.cacheConfig = config != null ? config : CacheConfig.DEFAULT;
75 this.validityPolicy = new CacheValidityPolicy(config);
76 this.responseGenerator = new CachedHttpResponseGenerator(this.validityPolicy);
77 this.cacheableRequestPolicy = new CacheableRequestPolicy();
78 this.suitabilityChecker = new CachedResponseSuitabilityChecker(this.validityPolicy, this.cacheConfig);
79 this.responseCachingPolicy = new ResponseCachingPolicy(
80 this.cacheConfig.isSharedCache(),
81 this.cacheConfig.isNeverCacheHTTP10ResponsesWithQuery(),
82 this.cacheConfig.isNeverCacheHTTP11ResponsesWithQuery());
83 }
84
85
86
87
88
89
90 public long getCacheHits() {
91 return cacheHits.get();
92 }
93
94
95
96
97
98
99 public long getCacheMisses() {
100 return cacheMisses.get();
101 }
102
103
104
105
106
107
108 public long getCacheUpdates() {
109 return cacheUpdates.get();
110 }
111
112 SimpleHttpResponse generateCachedResponse(
113 final HttpRequest request,
114 final HttpCacheEntry entry,
115 final Instant now) throws ResourceIOException {
116 if (shouldSendNotModifiedResponse(request, entry, now)) {
117 return responseGenerator.generateNotModifiedResponse(entry);
118 } else {
119 return responseGenerator.generateResponse(request, entry);
120 }
121 }
122
123 SimpleHttpResponse generateGatewayTimeout() {
124 return SimpleHttpResponse.create(HttpStatus.SC_GATEWAY_TIMEOUT, "Gateway Timeout");
125 }
126
127 SimpleHttpResponse unvalidatedCacheHit(final HttpRequest request, final HttpCacheEntry entry) throws IOException {
128 return responseGenerator.generateResponse(request, entry);
129 }
130
131 Instant getCurrentDate() {
132 return Instant.now();
133 }
134
135 boolean clientRequestsOurOptions(final HttpRequest request) {
136 if (!Method.OPTIONS.isSame(request.getMethod())) {
137 return false;
138 }
139
140 if (!"*".equals(request.getRequestUri())) {
141 return false;
142 }
143
144 final Header h = request.getFirstHeader(HttpHeaders.MAX_FORWARDS);
145 return "0".equals(h != null ? h.getValue() : null);
146 }
147
148 boolean shouldSendNotModifiedResponse(final HttpRequest request, final HttpCacheEntry responseEntry, final Instant now) {
149 return suitabilityChecker.isConditional(request)
150 && suitabilityChecker.allConditionalsMatch(request, responseEntry, now);
151 }
152
153 boolean staleIfErrorAppliesTo(final int statusCode) {
154 return statusCode == HttpStatus.SC_INTERNAL_SERVER_ERROR
155 || statusCode == HttpStatus.SC_BAD_GATEWAY
156 || statusCode == HttpStatus.SC_SERVICE_UNAVAILABLE
157 || statusCode == HttpStatus.SC_GATEWAY_TIMEOUT;
158 }
159
160
161
162
163
164
165
166
167
168 void storeRequestIfModifiedSinceFor304Response(final HttpRequest request, final HttpResponse backendResponse) {
169 if (backendResponse.getCode() == HttpStatus.SC_NOT_MODIFIED) {
170 final Header h = request.getFirstHeader(HttpHeaders.IF_MODIFIED_SINCE);
171 if (h != null) {
172 backendResponse.addHeader(HttpHeaders.LAST_MODIFIED, h.getValue());
173 }
174 }
175 }
176
177 boolean isResponseTooBig(final EntityDetails entityDetails) {
178 if (entityDetails == null) {
179 return false;
180 }
181 final long contentLength = entityDetails.getContentLength();
182 if (contentLength == -1) {
183 return false;
184 }
185 final long maxObjectSize = cacheConfig.getMaxObjectSize();
186 return contentLength > maxObjectSize;
187 }
188
189 }