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 }
118 return responseGenerator.generateResponse(request, entry);
119 }
120
121 SimpleHttpResponse generateGatewayTimeout() {
122 return SimpleHttpResponse.create(HttpStatus.SC_GATEWAY_TIMEOUT, "Gateway Timeout");
123 }
124
125 Instant getCurrentDate() {
126 return Instant.now();
127 }
128
129 boolean clientRequestsOurOptions(final HttpRequest request) {
130 if (!Method.OPTIONS.isSame(request.getMethod())) {
131 return false;
132 }
133
134 if (!"*".equals(request.getRequestUri())) {
135 return false;
136 }
137
138 final Header h = request.getFirstHeader(HttpHeaders.MAX_FORWARDS);
139 return "0".equals(h != null ? h.getValue() : null);
140 }
141
142 boolean shouldSendNotModifiedResponse(final HttpRequest request, final HttpCacheEntry responseEntry, final Instant now) {
143 return suitabilityChecker.isConditional(request)
144 && suitabilityChecker.allConditionalsMatch(request, responseEntry, now);
145 }
146
147 boolean staleIfErrorAppliesTo(final int statusCode) {
148 return statusCode == HttpStatus.SC_INTERNAL_SERVER_ERROR
149 || statusCode == HttpStatus.SC_BAD_GATEWAY
150 || statusCode == HttpStatus.SC_SERVICE_UNAVAILABLE
151 || statusCode == HttpStatus.SC_GATEWAY_TIMEOUT;
152 }
153
154
155
156
157
158
159
160
161
162 void storeRequestIfModifiedSinceFor304Response(final HttpRequest request, final HttpResponse backendResponse) {
163 if (backendResponse.getCode() == HttpStatus.SC_NOT_MODIFIED) {
164 final Header h = request.getFirstHeader(HttpHeaders.IF_MODIFIED_SINCE);
165 if (h != null) {
166 backendResponse.addHeader(HttpHeaders.LAST_MODIFIED, h.getValue());
167 }
168 }
169 }
170
171 boolean isResponseTooBig(final EntityDetails entityDetails) {
172 if (entityDetails == null) {
173 return false;
174 }
175 final long contentLength = entityDetails.getContentLength();
176 if (contentLength == -1) {
177 return false;
178 }
179 final long maxObjectSize = cacheConfig.getMaxObjectSize();
180 return contentLength > maxObjectSize;
181 }
182
183 }