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