Serve latest version of plugin resources when cache is stale
When serving HTTP plugin resources from cache, we do need to check the cached lastModifiedDate against the underlying plugin entry latest update. If dates do not match, we need to fetch again the entry and return it back to the client, updating the in-memory cache. Without this fix, the in-memory cached copy was always returned even if the one on the file-system was actually updated. Change-Id: I36ee9989ade0640fb5ceda73749efb852d6c5801
This commit is contained in:

committed by
Dave Borowitz

parent
93169e9b0a
commit
44c0d1e906
@@ -24,6 +24,7 @@ import com.google.common.base.Strings;
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.common.net.HttpHeaders;
|
||||
import com.google.gerrit.extensions.registration.RegistrationHandle;
|
||||
import com.google.gerrit.httpd.restapi.RestApiServlet;
|
||||
import com.google.gerrit.server.MimeUtilFileTypeRegistry;
|
||||
@@ -260,7 +261,7 @@ class HttpPluginServlet extends HttpServlet
|
||||
String file = pathInfo.substring(1);
|
||||
ResourceKey key = new ResourceKey(holder.plugin, file);
|
||||
Resource rsc = resourceCache.getIfPresent(key);
|
||||
if (rsc != null) {
|
||||
if (rsc != null && req.getHeader(HttpHeaders.IF_MODIFIED_SINCE) == null) {
|
||||
rsc.send(req, res);
|
||||
return;
|
||||
}
|
||||
@@ -278,7 +279,11 @@ class HttpPluginServlet extends HttpServlet
|
||||
PluginContentScanner scanner = holder.plugin.getContentScanner();
|
||||
Optional<PluginEntry> entry = scanner.getEntry(file);
|
||||
if (entry.isPresent()) {
|
||||
sendResource(scanner, entry.get(), key, res);
|
||||
if (hasUpToDateCachedResource(rsc, entry.get().getTime())) {
|
||||
rsc.send(req, res);
|
||||
} else {
|
||||
sendResource(scanner, entry.get(), key, res);
|
||||
}
|
||||
} else {
|
||||
resourceCache.put(key, Resource.NOT_FOUND);
|
||||
Resource.NOT_FOUND.send(req, res);
|
||||
@@ -297,12 +302,26 @@ class HttpPluginServlet extends HttpServlet
|
||||
}
|
||||
if (!entry.isPresent() && file.endsWith("/index.html")) {
|
||||
String pfx = file.substring(0, file.length() - "index.html".length());
|
||||
sendAutoIndex(scanner, pfx, holder.plugin.getName(), key, res,
|
||||
holder.plugin.getSrcFile().lastModified());
|
||||
long pluginLastModified = holder.plugin.getSrcFile().lastModified();
|
||||
if (hasUpToDateCachedResource(rsc, pluginLastModified)) {
|
||||
rsc.send(req, res);
|
||||
} else {
|
||||
sendAutoIndex(scanner, pfx, holder.plugin.getName(), key, res,
|
||||
pluginLastModified);
|
||||
}
|
||||
} else if (entry.isPresent() && entry.get().getName().endsWith(".md")) {
|
||||
sendMarkdownAsHtml(scanner, entry.get(), holder.plugin.getName(), key, res);
|
||||
if (hasUpToDateCachedResource(rsc, entry.get().getTime())) {
|
||||
rsc.send(req, res);
|
||||
} else {
|
||||
sendMarkdownAsHtml(scanner, entry.get(), holder.plugin.getName(),
|
||||
key, res);
|
||||
}
|
||||
} else if (entry.isPresent()) {
|
||||
sendResource(scanner, entry.get(), key, res);
|
||||
if (hasUpToDateCachedResource(rsc, entry.get().getTime())) {
|
||||
rsc.send(req, res);
|
||||
} else {
|
||||
sendResource(scanner, entry.get(), key, res);
|
||||
}
|
||||
} else {
|
||||
resourceCache.put(key, Resource.NOT_FOUND);
|
||||
Resource.NOT_FOUND.send(req, res);
|
||||
@@ -313,6 +332,11 @@ class HttpPluginServlet extends HttpServlet
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasUpToDateCachedResource(Resource cachedResource, long lastUpdateTime) {
|
||||
return cachedResource != null
|
||||
&& cachedResource.isUnchanged(lastUpdateTime);
|
||||
}
|
||||
|
||||
private void appendEntriesSection(PluginContentScanner scanner, List<PluginEntry> entries,
|
||||
String sectionTitle, StringBuilder md, String prefix,
|
||||
int nameOffset) throws IOException {
|
||||
|
@@ -34,9 +34,17 @@ abstract class Resource {
|
||||
CacheHeaders.setNotCacheable(res);
|
||||
res.sendError(HttpServletResponse.SC_NOT_FOUND);
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isUnchanged(long latestModifiedDate) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
abstract boolean isUnchanged(long latestModifiedDate);
|
||||
|
||||
abstract int weigh();
|
||||
|
||||
abstract void send(HttpServletRequest req, HttpServletResponse res)
|
||||
throws IOException;
|
||||
}
|
||||
}
|
||||
|
@@ -71,4 +71,9 @@ final class SmallResource extends Resource {
|
||||
res.setContentLength(data.length);
|
||||
res.getOutputStream().write(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isUnchanged(long lastModified) {
|
||||
return this.lastModified == lastModified;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user