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