Issue #1340 Consistent optional use of query string in PushCacheFilter

This commit is contained in:
Greg Wilkins 2017-03-09 16:24:31 +11:00
parent 9f9e1ab190
commit 2219863c11
2 changed files with 26 additions and 18 deletions

View File

@ -704,7 +704,7 @@ public class PushCacheFilterTest extends AbstractTest
{
String name = "foo";
String value = "bar";
final String primaryResource = "/primary.html";
final String primaryResource = "/primary.html?"+name + "=" +value;
final String secondaryResource = "/secondary.html?" + name + "=" + value;
start(new HttpServlet()
{

View File

@ -73,6 +73,8 @@ import org.eclipse.jetty.util.log.Logger;
* secondary resources are pushed to the client, unless the request carries
* {@code If-xxx} header that hint that the client has the resources in its
* cache.</p>
* <p>If the init param useQueryInKey is set, then the query string is used as
* as part of the key to identify a resource</p>
*/
@ManagedObject("Push cache based on the HTTP 'Referer' header")
public class PushCacheFilter implements Filter
@ -85,6 +87,7 @@ public class PushCacheFilter implements Filter
private long _associatePeriod = 4000L;
private int _maxAssociations = 16;
private long _renew = System.nanoTime();
private boolean _useQueryInKey;
@Override
public void init(FilterConfig config) throws ServletException
@ -106,6 +109,8 @@ public class PushCacheFilter implements Filter
for (String p : StringUtil.csvSplit(ports))
_ports.add(Integer.parseInt(p));
_useQueryInKey = Boolean.parseBoolean(config.getInitParameter("useQueryInKey"));
// Expose for JMX.
config.getServletContext().setAttribute(config.getFilterName(), this);
@ -161,10 +166,13 @@ public class PushCacheFilter implements Filter
if (LOG.isDebugEnabled())
LOG.debug("{} {} referrer={} conditional={} synthetic={}", request.getMethod(), request.getRequestURI(), referrer, conditional, isPushRequest(request));
String path = URIUtil.addPaths(request.getServletPath(), request.getPathInfo());
String query = request.getQueryString();
if (query != null)
path += "?" + query;
String key = URIUtil.addPaths(request.getServletPath(), request.getPathInfo());
if (_useQueryInKey)
{
String query = request.getQueryString();
if (query != null)
key += "?" + query;
}
if (referrer != null)
{
HttpURI referrerURI = new HttpURI(referrer);
@ -180,13 +188,13 @@ public class PushCacheFilter implements Filter
{
if (HttpMethod.GET.is(request.getMethod()))
{
String referrerPath = referrerURI.getPath();
String referrerPath = _useQueryInKey?referrerURI.getPathQuery():referrerURI.getPath();
if (referrerPath == null)
referrerPath = "/";
if (referrerPath.startsWith(request.getContextPath()))
{
String referrerPathNoContext = referrerPath.substring(request.getContextPath().length());
if (!referrerPathNoContext.equals(path))
if (!referrerPathNoContext.equals(key))
{
PrimaryResource primaryResource = _cache.get(referrerPathNoContext);
if (primaryResource != null)
@ -194,29 +202,29 @@ public class PushCacheFilter implements Filter
long primaryTimestamp = primaryResource._timestamp.get();
if (primaryTimestamp != 0)
{
RequestDispatcher dispatcher = request.getServletContext().getRequestDispatcher(path);
RequestDispatcher dispatcher = request.getServletContext().getRequestDispatcher(key);
if (now - primaryTimestamp < TimeUnit.MILLISECONDS.toNanos(_associatePeriod))
{
ConcurrentMap<String, RequestDispatcher> associated = primaryResource._associated;
// Not strictly concurrent-safe, just best effort to limit associations.
if (associated.size() <= _maxAssociations)
{
if (associated.putIfAbsent(path, dispatcher) == null)
if (associated.putIfAbsent(key, dispatcher) == null)
{
if (LOG.isDebugEnabled())
LOG.debug("Associated {} to {}", path, referrerPathNoContext);
LOG.debug("Associated {} to {}", key, referrerPathNoContext);
}
}
else
{
if (LOG.isDebugEnabled())
LOG.debug("Not associated {} to {}, exceeded max associations of {}", path, referrerPathNoContext, _maxAssociations);
LOG.debug("Not associated {} to {}, exceeded max associations of {}", key, referrerPathNoContext, _maxAssociations);
}
}
else
{
if (LOG.isDebugEnabled())
LOG.debug("Not associated {} to {}, outside associate period of {}ms", path, referrerPathNoContext, _associatePeriod);
LOG.debug("Not associated {} to {}, outside associate period of {}ms", key, referrerPathNoContext, _associatePeriod);
}
}
}
@ -224,7 +232,7 @@ public class PushCacheFilter implements Filter
else
{
if (LOG.isDebugEnabled())
LOG.debug("Not associated {} to {}, referring to self", path, referrerPathNoContext);
LOG.debug("Not associated {} to {}, referring to self", key, referrerPathNoContext);
}
}
}
@ -236,15 +244,15 @@ public class PushCacheFilter implements Filter
}
}
PrimaryResource primaryResource = _cache.get(path);
PrimaryResource primaryResource = _cache.get(key);
if (primaryResource == null)
{
PrimaryResource r = new PrimaryResource();
primaryResource = _cache.putIfAbsent(path, r);
primaryResource = _cache.putIfAbsent(key, r);
primaryResource = primaryResource == null ? r : primaryResource;
primaryResource._timestamp.compareAndSet(0, now);
if (LOG.isDebugEnabled())
LOG.debug("Cached primary resource {}", path);
LOG.debug("Cached primary resource {}", key);
}
else
{
@ -253,7 +261,7 @@ public class PushCacheFilter implements Filter
{
primaryResource._associated.clear();
if (LOG.isDebugEnabled())
LOG.debug("Clear associated resources for {}", path);
LOG.debug("Clear associated resources for {}", key);
}
}
@ -274,7 +282,7 @@ public class PushCacheFilter implements Filter
Dispatcher dispatcher = (Dispatcher)entry.getValue();
if (LOG.isDebugEnabled())
LOG.debug("Pushing {} for {}", dispatcher, path);
LOG.debug("Pushing {} for {}", dispatcher, key);
dispatcher.push(request);
}
}