Search in sources :

Example 1 with PushBuilder

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);
}
Also used : Request(org.eclipse.jetty.server.Request) HttpServletRequest(javax.servlet.http.HttpServletRequest) ServletRequest(javax.servlet.ServletRequest) HttpURI(org.eclipse.jetty.http.HttpURI) ArrayDeque(java.util.ArrayDeque) HttpServletRequest(javax.servlet.http.HttpServletRequest) HttpHeader(org.eclipse.jetty.http.HttpHeader) HttpField(org.eclipse.jetty.http.HttpField) HttpFields(org.eclipse.jetty.http.HttpFields) PushBuilder(org.eclipse.jetty.server.PushBuilder)

Example 2 with PushBuilder

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);
}
Also used : HttpSession(javax.servlet.http.HttpSession) Request(org.eclipse.jetty.server.Request) ServletRequest(javax.servlet.ServletRequest) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) PushBuilder(org.eclipse.jetty.server.PushBuilder) ArrayDeque(java.util.ArrayDeque)

Aggregations

ArrayDeque (java.util.ArrayDeque)2 ServletRequest (javax.servlet.ServletRequest)2 PushBuilder (org.eclipse.jetty.server.PushBuilder)2 Request (org.eclipse.jetty.server.Request)2 ConcurrentHashMap (java.util.concurrent.ConcurrentHashMap)1 HttpServletRequest (javax.servlet.http.HttpServletRequest)1 HttpSession (javax.servlet.http.HttpSession)1 HttpField (org.eclipse.jetty.http.HttpField)1 HttpFields (org.eclipse.jetty.http.HttpFields)1 HttpHeader (org.eclipse.jetty.http.HttpHeader)1 HttpURI (org.eclipse.jetty.http.HttpURI)1