use of org.eclipse.jetty.server.PushBuilder in project jetty.project by eclipse.
the class PushCacheFilter method doFilter.
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
Request jettyRequest = Request.getBaseRequest(request);
if (HttpVersion.fromString(request.getProtocol()).getVersion() < 20 || !HttpMethod.GET.is(request.getMethod()) || !jettyRequest.isPushSupported()) {
chain.doFilter(req, resp);
return;
}
long now = System.nanoTime();
// Iterating over fields is more efficient than multiple gets
HttpFields fields = jettyRequest.getHttpFields();
boolean conditional = false;
String referrer = null;
loop: for (int i = 0; i < fields.size(); i++) {
HttpField field = fields.getField(i);
HttpHeader header = field.getHeader();
if (header == null)
continue;
switch(header) {
case IF_MATCH:
case IF_MODIFIED_SINCE:
case IF_NONE_MATCH:
case IF_UNMODIFIED_SINCE:
conditional = true;
break loop;
case REFERER:
referrer = field.getValue();
break;
default:
break;
}
}
if (LOG.isDebugEnabled())
LOG.debug("{} {} referrer={} conditional={}", request.getMethod(), request.getRequestURI(), referrer, conditional);
String path = request.getRequestURI();
String query = request.getQueryString();
if (_useQueryInKey && query != null)
path += "?" + query;
if (referrer != null) {
HttpURI referrerURI = new HttpURI(referrer);
String host = referrerURI.getHost();
int port = referrerURI.getPort();
if (port <= 0)
port = request.isSecure() ? 443 : 80;
boolean referredFromHere = _hosts.size() > 0 ? _hosts.contains(host) : host.equals(request.getServerName());
referredFromHere &= _ports.size() > 0 ? _ports.contains(port) : port == request.getServerPort();
if (referredFromHere) {
if (HttpMethod.GET.is(request.getMethod())) {
String referrerPath = _useQueryInKey ? referrerURI.getPathQuery() : referrerURI.getPath();
if (referrerPath == null)
referrerPath = "/";
if (referrerPath.startsWith(request.getContextPath() + "/")) {
if (!referrerPath.equals(path)) {
PrimaryResource primaryResource = _cache.get(referrerPath);
if (primaryResource != null) {
long primaryTimestamp = primaryResource._timestamp.get();
if (primaryTimestamp != 0) {
if (now - primaryTimestamp < TimeUnit.MILLISECONDS.toNanos(_associatePeriod)) {
Set<String> associated = primaryResource._associated;
// Not strictly concurrent-safe, just best effort to limit associations.
if (associated.size() <= _maxAssociations) {
if (associated.add(path)) {
if (LOG.isDebugEnabled())
LOG.debug("Associated {} to {}", path, referrerPath);
}
} else {
if (LOG.isDebugEnabled())
LOG.debug("Not associated {} to {}, exceeded max associations of {}", path, referrerPath, _maxAssociations);
}
} else {
if (LOG.isDebugEnabled())
LOG.debug("Not associated {} to {}, outside associate period of {}ms", path, referrerPath, _associatePeriod);
}
}
}
} else {
if (LOG.isDebugEnabled())
LOG.debug("Not associated {} to {}, referring to self", path, referrerPath);
}
} else {
if (LOG.isDebugEnabled())
LOG.debug("Not associated {} to {}, different context", path, referrerPath);
}
}
} else {
if (LOG.isDebugEnabled())
LOG.debug("External referrer {}", referrer);
}
}
PrimaryResource primaryResource = _cache.get(path);
if (primaryResource == null) {
PrimaryResource r = new PrimaryResource();
primaryResource = _cache.putIfAbsent(path, r);
primaryResource = primaryResource == null ? r : primaryResource;
primaryResource._timestamp.compareAndSet(0, now);
if (LOG.isDebugEnabled())
LOG.debug("Cached primary resource {}", path);
} else {
long last = primaryResource._timestamp.get();
if (last < _renew && primaryResource._timestamp.compareAndSet(last, now)) {
primaryResource._associated.clear();
if (LOG.isDebugEnabled())
LOG.debug("Clear associated resources for {}", path);
}
}
// Push associated resources.
if (!conditional && !primaryResource._associated.isEmpty()) {
PushBuilder pushBuilder = jettyRequest.getPushBuilder();
// Breadth-first push of associated resources.
Queue<PrimaryResource> queue = new ArrayDeque<>();
queue.offer(primaryResource);
while (!queue.isEmpty()) {
PrimaryResource parent = queue.poll();
for (String childPath : parent._associated) {
PrimaryResource child = _cache.get(childPath);
if (child != null)
queue.offer(child);
if (LOG.isDebugEnabled())
LOG.debug("Pushing {} for {}", childPath, path);
pushBuilder.path(childPath).push();
}
}
}
chain.doFilter(request, resp);
}
use of org.eclipse.jetty.server.PushBuilder in project jetty.project by eclipse.
the class PushSessionCacheFilter method doFilter.
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// Get Jetty request as these APIs are not yet standard
Request baseRequest = Request.getBaseRequest(request);
String uri = baseRequest.getRequestURI();
if (LOG.isDebugEnabled())
LOG.debug("{} {} push={}", baseRequest.getMethod(), uri, baseRequest.isPush());
HttpSession session = baseRequest.getSession(true);
// find the target for this resource
Target target = _cache.get(uri);
if (target == null) {
Target t = new Target(uri);
target = _cache.putIfAbsent(uri, t);
target = target == null ? t : target;
}
request.setAttribute(TARGET_ATTR, target);
// Set the timestamp for this resource in this session
ConcurrentHashMap<String, Long> timestamps = (ConcurrentHashMap<String, Long>) session.getAttribute(TIMESTAMP_ATTR);
if (timestamps == null) {
timestamps = new ConcurrentHashMap<>();
session.setAttribute(TIMESTAMP_ATTR, timestamps);
}
timestamps.put(uri, System.currentTimeMillis());
// push any associated resources
if (baseRequest.isPushSupported() && !baseRequest.isPush() && !target._associated.isEmpty()) {
// Breadth-first push of associated resources.
Queue<Target> queue = new ArrayDeque<>();
queue.offer(target);
while (!queue.isEmpty()) {
Target parent = queue.poll();
PushBuilder builder = baseRequest.getPushBuilder();
builder.addHeader("X-Pusher", PushSessionCacheFilter.class.toString());
for (Target child : parent._associated.values()) {
queue.offer(child);
String path = child._path;
if (LOG.isDebugEnabled())
LOG.debug("PUSH {} <- {}", path, uri);
builder.path(path).etag(child._etag).lastModified(child._lastModified).push();
}
}
}
chain.doFilter(request, response);
}
Aggregations