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:
Luca Milanesio
2014-06-20 14:30:58 +01:00
committed by Dave Borowitz
parent 93169e9b0a
commit 44c0d1e906
3 changed files with 44 additions and 7 deletions

View File

@@ -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 {

View File

@@ -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;
}
}

View File

@@ -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;
}
}