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