Search in sources :

Example 11 with ETag

use of io.undertow.util.ETag in project undertow by undertow-io.

the class ResponseCache method tryServeResponse.

/**
 * Attempts to serve the response from a cache.
 * <p>
 * If this fails, and the markCachable parameter is true then the response will be considered cachable,
 * and may be cached to be served by future handlers.
 * <p>
 * If this returns true then the caller should not modify the exchange any more, as this
 * can result in a handoff to an IO thread
 *
 * @param markCacheable If this is true then the resulting response will be considered cachable
 * @return <code>true</code> if serving succeeded,
 */
public boolean tryServeResponse(boolean markCacheable) {
    final CachedHttpRequest key = new CachedHttpRequest(exchange);
    DirectBufferCache.CacheEntry entry = cache.get(key);
    // we only cache get and head requests
    if (!exchange.getRequestMethod().equals(GET) && !exchange.getRequestMethod().equals(HEAD)) {
        return false;
    }
    if (entry == null) {
        this.responseCachable = markCacheable;
        return false;
    }
    // It's loading retry later
    if (!entry.enabled() || !entry.reference()) {
        this.responseCachable = markCacheable;
        return false;
    }
    CachedHttpRequest existingKey = (CachedHttpRequest) entry.key();
    // if any of the header matches fail we just return
    // we don't can the request, as it is possible the underlying handler
    // may have additional etags
    final ETag etag = existingKey.getEtag();
    if (!ETagUtils.handleIfMatch(exchange, etag, false)) {
        return false;
    }
    // we do send a 304 if the if-none-match header matches
    if (!ETagUtils.handleIfNoneMatch(exchange, etag, true)) {
        exchange.setStatusCode(StatusCodes.NOT_MODIFIED);
        exchange.endExchange();
        return true;
    }
    // the server may have a more up to date representation
    if (!DateUtils.handleIfUnmodifiedSince(exchange, existingKey.getLastModified())) {
        return false;
    }
    if (!DateUtils.handleIfModifiedSince(exchange, existingKey.getLastModified())) {
        exchange.setStatusCode(StatusCodes.NOT_MODIFIED);
        exchange.endExchange();
        return true;
    }
    // we are going to proceed. Set the appropriate headers
    if (existingKey.getContentType() != null) {
        exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, existingKey.getContentType());
    }
    if (existingKey.getContentEncoding() != null && !Headers.IDENTITY.equals(HttpString.tryFromString(existingKey.getContentEncoding()))) {
        exchange.getResponseHeaders().put(Headers.CONTENT_ENCODING, existingKey.getContentEncoding());
    }
    if (existingKey.getLastModified() != null) {
        exchange.getResponseHeaders().put(Headers.LAST_MODIFIED, DateUtils.toDateString(existingKey.getLastModified()));
    }
    if (existingKey.getContentLocation() != null) {
        exchange.getResponseHeaders().put(Headers.CONTENT_LOCATION, existingKey.getContentLocation());
    }
    if (existingKey.getLanguage() != null) {
        exchange.getResponseHeaders().put(Headers.CONTENT_LANGUAGE, existingKey.getLanguage());
    }
    if (etag != null) {
        exchange.getResponseHeaders().put(Headers.CONTENT_LANGUAGE, etag.toString());
    }
    // TODO: support if-range
    exchange.getResponseHeaders().put(Headers.CONTENT_LENGTH, Long.toString(entry.size()));
    if (exchange.getRequestMethod().equals(HEAD)) {
        exchange.endExchange();
        return true;
    }
    final ByteBuffer[] buffers;
    boolean ok = false;
    try {
        LimitedBufferSlicePool.PooledByteBuffer[] pooled = entry.buffers();
        buffers = new ByteBuffer[pooled.length];
        for (int i = 0; i < buffers.length; i++) {
            // Keep position from mutating
            buffers[i] = pooled[i].getBuffer().duplicate();
        }
        ok = true;
    } finally {
        if (!ok) {
            entry.dereference();
        }
    }
    // Transfer Inline, or register and continue transfer
    // Pass off the entry dereference call to the listener
    exchange.getResponseSender().send(buffers, new DereferenceCallback(entry));
    return true;
}
Also used : ETag(io.undertow.util.ETag) ByteBuffer(java.nio.ByteBuffer)

Aggregations

ETag (io.undertow.util.ETag)11 HttpServerExchange (io.undertow.server.HttpServerExchange)4 Date (java.util.Date)4 ByteRange (io.undertow.util.ByteRange)3 ByteBuffer (java.nio.ByteBuffer)3 Test (org.junit.Test)3 HttpHandler (io.undertow.server.HttpHandler)2 RangeAwareResource (io.undertow.server.handlers.resource.RangeAwareResource)2 ResourceManager (io.undertow.server.handlers.resource.ResourceManager)2 IOException (java.io.IOException)2 Path (java.nio.file.Path)2 Splitter (com.google.common.base.Splitter)1 Iterables (com.google.common.collect.Iterables)1 GzippableHttpBody (io.divolte.server.js.GzippableHttpBody)1 HttpBody (io.divolte.server.js.HttpBody)1 JavaScriptResource (io.divolte.server.js.JavaScriptResource)1 IoCallback (io.undertow.io.IoCallback)1 Sender (io.undertow.io.Sender)1 ResponseCache (io.undertow.server.handlers.cache.ResponseCache)1 ContentEncodedResource (io.undertow.server.handlers.encoding.ContentEncodedResource)1