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.net.URI;
30
31 import org.apache.hc.client5.http.cache.HttpCacheEntry;
32 import org.apache.hc.client5.http.cache.HttpCacheInvalidator;
33 import org.apache.hc.client5.http.cache.HttpCacheStorage;
34 import org.apache.hc.client5.http.cache.ResourceIOException;
35 import org.apache.hc.client5.http.utils.URIUtils;
36 import org.apache.hc.core5.annotation.Contract;
37 import org.apache.hc.core5.annotation.Internal;
38 import org.apache.hc.core5.annotation.ThreadingBehavior;
39 import org.apache.hc.core5.function.Resolver;
40 import org.apache.hc.core5.http.Header;
41 import org.apache.hc.core5.http.HttpHeaders;
42 import org.apache.hc.core5.http.HttpHost;
43 import org.apache.hc.core5.http.HttpRequest;
44 import org.apache.hc.core5.http.HttpResponse;
45 import org.slf4j.Logger;
46 import org.slf4j.LoggerFactory;
47
48
49
50
51
52
53
54 @Contract(threading = ThreadingBehavior.STATELESS)
55 @Internal
56 public class DefaultCacheInvalidator extends CacheInvalidatorBase implements HttpCacheInvalidator {
57
58 public static final DefaultCacheInvalidator INSTANCE = new DefaultCacheInvalidator();
59
60 private static final Logger LOG = LoggerFactory.getLogger(DefaultCacheInvalidator.class);
61
62 private HttpCacheEntry getEntry(final HttpCacheStorage storage, final String cacheKey) {
63 try {
64 return storage.getEntry(cacheKey);
65 } catch (final ResourceIOException ex) {
66 if (LOG.isWarnEnabled()) {
67 LOG.warn("Unable to get cache entry with key {}", cacheKey, ex);
68 }
69 return null;
70 }
71 }
72
73 private void removeEntry(final HttpCacheStorage storage, final String cacheKey) {
74 try {
75 storage.removeEntry(cacheKey);
76 } catch (final ResourceIOException ex) {
77 if (LOG.isWarnEnabled()) {
78 LOG.warn("Unable to flush cache entry with key {}", cacheKey, ex);
79 }
80 }
81 }
82
83 @Override
84 public void flushCacheEntriesInvalidatedByRequest(
85 final HttpHost host,
86 final HttpRequest request,
87 final Resolver<URI, String> cacheKeyResolver,
88 final HttpCacheStorage storage) {
89 final String s = HttpCacheSupport.getRequestUri(request, host);
90 final URI uri = HttpCacheSupport.normalizeQuietly(s);
91 final String cacheKey = uri != null ? cacheKeyResolver.resolve(uri) : s;
92 final HttpCacheEntry parent = getEntry(storage, cacheKey);
93
94 if (requestShouldNotBeCached(request) || shouldInvalidateHeadCacheEntry(request, parent)) {
95 if (parent != null) {
96 if (LOG.isDebugEnabled()) {
97 LOG.debug("Invalidating parent cache entry with key {}", cacheKey);
98 }
99 for (final String variantURI : parent.getVariantMap().values()) {
100 removeEntry(storage, variantURI);
101 }
102 removeEntry(storage, cacheKey);
103 }
104 if (uri != null) {
105 if (LOG.isWarnEnabled()) {
106 LOG.warn("{} is not a valid URI", s);
107 }
108 final Header clHdr = request.getFirstHeader(HttpHeaders.CONTENT_LOCATION);
109 if (clHdr != null) {
110 final URI contentLocation = HttpCacheSupport.normalizeQuietly(clHdr.getValue());
111 if (contentLocation != null) {
112 if (!flushAbsoluteUriFromSameHost(uri, contentLocation, cacheKeyResolver, storage)) {
113 flushRelativeUriFromSameHost(uri, contentLocation, cacheKeyResolver, storage);
114 }
115 }
116 }
117 final Header lHdr = request.getFirstHeader(HttpHeaders.LOCATION);
118 if (lHdr != null) {
119 final URI location = HttpCacheSupport.normalizeQuietly(lHdr.getValue());
120 if (location != null) {
121 flushAbsoluteUriFromSameHost(uri, location, cacheKeyResolver, storage);
122 }
123 }
124 }
125 }
126 }
127
128 private void flushRelativeUriFromSameHost(
129 final URI requestUri,
130 final URI uri,
131 final Resolver<URI, String> cacheKeyResolver,
132 final HttpCacheStorage storage) {
133 final URI resolvedUri = uri != null ? URIUtils.resolve(requestUri, uri) : null;
134 if (resolvedUri != null && isSameHost(requestUri, resolvedUri)) {
135 removeEntry(storage, cacheKeyResolver.resolve(resolvedUri));
136 }
137 }
138
139 private boolean flushAbsoluteUriFromSameHost(
140 final URI requestUri,
141 final URI uri,
142 final Resolver<URI, String> cacheKeyResolver,
143 final HttpCacheStorage storage) {
144 if (uri != null && isSameHost(requestUri, uri)) {
145 removeEntry(storage, cacheKeyResolver.resolve(uri));
146 return true;
147 }
148 return false;
149 }
150
151 @Override
152 public void flushCacheEntriesInvalidatedByExchange(
153 final HttpHost host,
154 final HttpRequest request,
155 final HttpResponse response,
156 final Resolver<URI, String> cacheKeyResolver,
157 final HttpCacheStorage storage) {
158 final int status = response.getCode();
159 if (status < 200 || status > 299) {
160 return;
161 }
162 final String s = HttpCacheSupport.getRequestUri(request, host);
163 final URI uri = HttpCacheSupport.normalizeQuietly(s);
164 if (uri == null) {
165 return;
166 }
167 final URI contentLocation = getContentLocationURI(uri, response);
168 if (contentLocation != null && isSameHost(uri, contentLocation)) {
169 flushLocationCacheEntry(response, contentLocation, storage, cacheKeyResolver);
170 }
171 final URI location = getLocationURI(uri, response);
172 if (location != null && isSameHost(uri, location)) {
173 flushLocationCacheEntry(response, location, storage, cacheKeyResolver);
174 }
175 }
176
177 private void flushLocationCacheEntry(
178 final HttpResponse response,
179 final URI location,
180 final HttpCacheStorage storage,
181 final Resolver<URI, String> cacheKeyResolver) {
182 final String cacheKey = cacheKeyResolver.resolve(location);
183 final HttpCacheEntry entry = getEntry(storage, cacheKey);
184 if (entry != null) {
185
186
187
188 if (!responseDateOlderThanEntryDate(response, entry) && responseAndEntryEtagsDiffer(response, entry)) {
189 removeEntry(storage, cacheKey);
190 }
191 }
192 }
193
194 }