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 }