use of io.undertow.util.ETag in project divolte-collector by divolte.
the class JavaScriptHandler method handleRequest.
@Override
public void handleRequest(final HttpServerExchange exchange) throws Exception {
if (logger.isDebugEnabled()) {
logger.debug("Requested received for {} from {}", resource.getResourceName(), exchange.getSourceAddress().getHostString());
}
// Start with headers that we always set the same way.
final HeaderMap responseHeaders = exchange.getResponseHeaders();
responseHeaders.put(Headers.CACHE_CONTROL, CACHE_CONTROL_HEADER_VALUE);
// Figure out if we possibly need to deal with a compressed response,
// based on client capability.
final GzippableHttpBody uncompressedBody = resource.getEntityBody();
final Optional<HttpBody> gzippedBody = uncompressedBody.getGzippedBody();
final HttpBody bodyToSend;
if (gzippedBody.isPresent()) {
/*
* Compressed responses can use Content-Encoding and/or Transfer-Encoding.
* The semantics differ slightly, but it is suffice to say that most user
* agents don't advertise their Transfer-Encoding support.
* So for now we only support the Content-Encoding mechanism.
* Some other notes:
* - Some clients implement 'deflate' incorrectly. Hence we only support 'gzip',
* despite it having slightly more overhead.
* - We don't use Undertow's built-in compression support because we've
* pre-calculated the compressed response and expect to serve it up
* repeatedly, instead of calculating it on-the-fly for every request.
*/
responseHeaders.put(Headers.VARY, Headers.ACCEPT_ENCODING_STRING);
final HeaderValues acceptEncoding = exchange.getRequestHeaders().get(Headers.ACCEPT_ENCODING);
if (null != acceptEncoding && acceptEncoding.stream().anyMatch((header) -> Iterables.contains(HEADER_SPLITTER.split(header), "gzip"))) {
responseHeaders.put(Headers.CONTENT_ENCODING, "gzip");
bodyToSend = gzippedBody.get();
} else {
bodyToSend = uncompressedBody;
}
} else {
bodyToSend = uncompressedBody;
}
// Now we know which version of the entity is visible to this user-agent,
// figure out if the client already has the current version or not.
final ETag eTag = bodyToSend.getETag();
responseHeaders.put(Headers.ETAG, eTag.toString());
if (ETagUtils.handleIfNoneMatch(exchange, eTag, true)) {
final ByteBuffer entityBody = bodyToSend.getBody();
responseHeaders.put(Headers.CONTENT_TYPE, "application/javascript");
exchange.getResponseSender().send(entityBody);
} else {
exchange.setStatusCode(StatusCodes.NOT_MODIFIED);
exchange.endExchange();
}
}
use of io.undertow.util.ETag in project divolte-collector by divolte.
the class JavaScriptResource method generateETag.
private static ETag generateETag(final byte[] entityBytes) {
final MessageDigest digester = createDigester();
final byte[] digest = digester.digest(entityBytes);
return new ETag(false, Base64.getEncoder().encodeToString(digest));
}
use of io.undertow.util.ETag in project undertow by undertow-io.
the class DefaultServlet method serveFileBlocking.
private void serveFileBlocking(final HttpServletRequest req, final HttpServletResponse resp, final Resource resource, HttpServerExchange exchange) throws IOException {
final ETag etag = resource.getETag();
final Date lastModified = resource.getLastModified();
if (req.getDispatcherType() != DispatcherType.INCLUDE) {
if (!ETagUtils.handleIfMatch(req.getHeader(Headers.IF_MATCH_STRING), etag, false) || !DateUtils.handleIfUnmodifiedSince(req.getHeader(Headers.IF_UNMODIFIED_SINCE_STRING), lastModified)) {
resp.setStatus(StatusCodes.PRECONDITION_FAILED);
return;
}
if (!ETagUtils.handleIfNoneMatch(req.getHeader(Headers.IF_NONE_MATCH_STRING), etag, true) || !DateUtils.handleIfModifiedSince(req.getHeader(Headers.IF_MODIFIED_SINCE_STRING), lastModified)) {
if (req.getMethod().equals(Methods.GET_STRING) || req.getMethod().equals(Methods.HEAD_STRING)) {
resp.setStatus(StatusCodes.NOT_MODIFIED);
} else {
resp.setStatus(StatusCodes.PRECONDITION_FAILED);
}
return;
}
}
// we are going to proceed. Set the appropriate headers
if (resp.getContentType() == null) {
if (!resource.isDirectory()) {
final String contentType = deployment.getServletContext().getMimeType(resource.getName());
if (contentType != null) {
resp.setContentType(contentType);
} else {
resp.setContentType("application/octet-stream");
}
}
}
if (lastModified != null) {
resp.setHeader(Headers.LAST_MODIFIED_STRING, resource.getLastModifiedString());
}
if (etag != null) {
resp.setHeader(Headers.ETAG_STRING, etag.toString());
}
ByteRange.RangeResponseResult rangeResponse = null;
long start = -1, end = -1;
try {
// only set the content length if we are using a stream
// if we are using a writer who knows what the length will end up being
// todo: if someone installs a filter this can cause problems
// not sure how best to deal with this
// we also can't deal with range requests if a writer is in use
Long contentLength = resource.getContentLength();
if (contentLength != null) {
resp.getOutputStream();
if (contentLength > Integer.MAX_VALUE) {
resp.setContentLengthLong(contentLength);
} else {
resp.setContentLength(contentLength.intValue());
}
if (resource instanceof RangeAwareResource && ((RangeAwareResource) resource).isRangeSupported() && resource.getContentLength() != null) {
resp.setHeader(Headers.ACCEPT_RANGES_STRING, "bytes");
// TODO: figure out what to do with the content encoded resource manager
final ByteRange range = ByteRange.parse(req.getHeader(Headers.RANGE_STRING));
if (range != null) {
rangeResponse = range.getResponseResult(resource.getContentLength(), req.getHeader(Headers.IF_RANGE_STRING), resource.getLastModified(), resource.getETag() == null ? null : resource.getETag().getTag());
if (rangeResponse != null) {
start = rangeResponse.getStart();
end = rangeResponse.getEnd();
resp.setStatus(rangeResponse.getStatusCode());
resp.setHeader(Headers.CONTENT_RANGE_STRING, rangeResponse.getContentRange());
long length = rangeResponse.getContentLength();
if (length > Integer.MAX_VALUE) {
resp.setContentLengthLong(length);
} else {
resp.setContentLength((int) length);
}
if (rangeResponse.getStatusCode() == StatusCodes.REQUEST_RANGE_NOT_SATISFIABLE) {
return;
}
}
}
}
}
} catch (IllegalStateException e) {
}
final boolean include = req.getDispatcherType() == DispatcherType.INCLUDE;
if (!req.getMethod().equals(Methods.HEAD_STRING)) {
if (rangeResponse == null) {
resource.serve(exchange.getResponseSender(), exchange, completionCallback(include));
} else {
((RangeAwareResource) resource).serveRange(exchange.getResponseSender(), exchange, start, end, completionCallback(include));
}
}
}
use of io.undertow.util.ETag in project undertow by undertow-io.
the class DirectoryUtils method sendRequestedBlobs.
/**
* Serve static resource for the directory listing
*
* @param exchange The exchange
* @return true if resources were served
*/
public static boolean sendRequestedBlobs(HttpServerExchange exchange) {
ByteBuffer buffer = null;
String type = null;
String etag = null;
String quotedEtag = null;
if ("css".equals(exchange.getQueryString())) {
buffer = Blobs.FILE_CSS_BUFFER.duplicate();
type = "text/css";
etag = Blobs.FILE_CSS_ETAG;
quotedEtag = Blobs.FILE_CSS_ETAG_QUOTED;
} else if ("js".equals(exchange.getQueryString())) {
buffer = Blobs.FILE_JS_BUFFER.duplicate();
type = "application/javascript";
etag = Blobs.FILE_JS_ETAG;
quotedEtag = Blobs.FILE_JS_ETAG_QUOTED;
}
if (buffer != null) {
if (!ETagUtils.handleIfNoneMatch(exchange, new ETag(false, etag), false)) {
exchange.setStatusCode(StatusCodes.NOT_MODIFIED);
return true;
}
exchange.getResponseHeaders().put(Headers.CONTENT_LENGTH, String.valueOf(buffer.limit()));
exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, type);
exchange.getResponseHeaders().put(Headers.ETAG, quotedEtag);
if (Methods.HEAD.equals(exchange.getRequestMethod())) {
exchange.endExchange();
return true;
}
exchange.getResponseSender().send(buffer);
return true;
}
return false;
}
use of io.undertow.util.ETag in project undertow by undertow-io.
the class ResourceHandler method serveResource.
private void serveResource(final HttpServerExchange exchange, final boolean sendContent) throws Exception {
if (DirectoryUtils.sendRequestedBlobs(exchange)) {
return;
}
if (!allowed.resolve(exchange)) {
exchange.setStatusCode(StatusCodes.FORBIDDEN);
exchange.endExchange();
return;
}
ResponseCache cache = exchange.getAttachment(ResponseCache.ATTACHMENT_KEY);
final boolean cachable = this.cachable.resolve(exchange);
// we set caching headers before we try and serve from the cache
if (cachable && cacheTime != null) {
exchange.getResponseHeaders().put(Headers.CACHE_CONTROL, "public, max-age=" + cacheTime);
long date = System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(cacheTime);
String dateHeader = DateUtils.toDateString(new Date(date));
exchange.getResponseHeaders().put(Headers.EXPIRES, dateHeader);
}
if (cache != null && cachable) {
if (cache.tryServeResponse()) {
return;
}
}
// we now dispatch to a worker thread
// as resource manager methods are potentially blocking
HttpHandler dispatchTask = new HttpHandler() {
@Override
public void handleRequest(HttpServerExchange exchange) throws Exception {
Resource resource = null;
try {
if (File.separatorChar == '/' || !exchange.getRelativePath().contains(File.separator)) {
// we don't process resources that contain the sperator character if this is not /
// this prevents attacks where people use windows path seperators in file URLS's
resource = resourceSupplier.getResource(exchange, canonicalize(exchange.getRelativePath()));
}
} catch (IOException e) {
clearCacheHeaders(exchange);
UndertowLogger.REQUEST_IO_LOGGER.ioException(e);
exchange.setStatusCode(StatusCodes.INTERNAL_SERVER_ERROR);
exchange.endExchange();
return;
}
if (resource == null) {
clearCacheHeaders(exchange);
// usually a 404 handler
next.handleRequest(exchange);
return;
}
if (resource.isDirectory()) {
Resource indexResource;
try {
indexResource = getIndexFiles(exchange, resourceSupplier, resource.getPath(), welcomeFiles);
} catch (IOException e) {
UndertowLogger.REQUEST_IO_LOGGER.ioException(e);
exchange.setStatusCode(StatusCodes.INTERNAL_SERVER_ERROR);
exchange.endExchange();
return;
}
if (indexResource == null) {
if (directoryListingEnabled) {
DirectoryUtils.renderDirectoryListing(exchange, resource);
return;
} else {
exchange.setStatusCode(StatusCodes.FORBIDDEN);
exchange.endExchange();
return;
}
} else if (!exchange.getRequestPath().endsWith("/")) {
exchange.setStatusCode(StatusCodes.FOUND);
exchange.getResponseHeaders().put(Headers.LOCATION, RedirectBuilder.redirect(exchange, exchange.getRelativePath() + "/", true));
exchange.endExchange();
return;
}
resource = indexResource;
} else if (exchange.getRelativePath().endsWith("/")) {
// UNDERTOW-432
exchange.setStatusCode(StatusCodes.NOT_FOUND);
exchange.endExchange();
return;
}
final ETag etag = resource.getETag();
final Date lastModified = resource.getLastModified();
if (!ETagUtils.handleIfMatch(exchange, etag, false) || !DateUtils.handleIfUnmodifiedSince(exchange, lastModified)) {
exchange.setStatusCode(StatusCodes.PRECONDITION_FAILED);
exchange.endExchange();
return;
}
if (!ETagUtils.handleIfNoneMatch(exchange, etag, true) || !DateUtils.handleIfModifiedSince(exchange, lastModified)) {
exchange.setStatusCode(StatusCodes.NOT_MODIFIED);
exchange.endExchange();
return;
}
final ContentEncodedResourceManager contentEncodedResourceManager = ResourceHandler.this.contentEncodedResourceManager;
Long contentLength = resource.getContentLength();
if (contentLength != null && !exchange.getResponseHeaders().contains(Headers.TRANSFER_ENCODING)) {
exchange.setResponseContentLength(contentLength);
}
ByteRange.RangeResponseResult rangeResponse = null;
long start = -1, end = -1;
if (resource instanceof RangeAwareResource && ((RangeAwareResource) resource).isRangeSupported() && contentLength != null && contentEncodedResourceManager == null) {
exchange.getResponseHeaders().put(Headers.ACCEPT_RANGES, "bytes");
// TODO: figure out what to do with the content encoded resource manager
ByteRange range = ByteRange.parse(exchange.getRequestHeaders().getFirst(Headers.RANGE));
if (range != null && range.getRanges() == 1 && resource.getContentLength() != null) {
rangeResponse = range.getResponseResult(resource.getContentLength(), exchange.getRequestHeaders().getFirst(Headers.IF_RANGE), resource.getLastModified(), resource.getETag() == null ? null : resource.getETag().getTag());
if (rangeResponse != null) {
start = rangeResponse.getStart();
end = rangeResponse.getEnd();
exchange.setStatusCode(rangeResponse.getStatusCode());
exchange.getResponseHeaders().put(Headers.CONTENT_RANGE, rangeResponse.getContentRange());
long length = rangeResponse.getContentLength();
exchange.setResponseContentLength(length);
if (rangeResponse.getStatusCode() == StatusCodes.REQUEST_RANGE_NOT_SATISFIABLE) {
return;
}
}
}
}
if (!exchange.getResponseHeaders().contains(Headers.CONTENT_TYPE)) {
final String contentType = resource.getContentType(mimeMappings);
if (contentType != null) {
exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, contentType);
} else {
exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "application/octet-stream");
}
}
if (lastModified != null) {
exchange.getResponseHeaders().put(Headers.LAST_MODIFIED, resource.getLastModifiedString());
}
if (etag != null) {
exchange.getResponseHeaders().put(Headers.ETAG, etag.toString());
}
if (contentEncodedResourceManager != null) {
try {
ContentEncodedResource encoded = contentEncodedResourceManager.getResource(resource, exchange);
if (encoded != null) {
exchange.getResponseHeaders().put(Headers.CONTENT_ENCODING, encoded.getContentEncoding());
exchange.getResponseHeaders().put(Headers.CONTENT_LENGTH, encoded.getResource().getContentLength());
encoded.getResource().serve(exchange.getResponseSender(), exchange, IoCallback.END_EXCHANGE);
return;
}
} catch (IOException e) {
// TODO: should this be fatal
UndertowLogger.REQUEST_IO_LOGGER.ioException(e);
exchange.setStatusCode(StatusCodes.INTERNAL_SERVER_ERROR);
exchange.endExchange();
return;
}
}
if (!sendContent) {
exchange.endExchange();
} else if (rangeResponse != null) {
((RangeAwareResource) resource).serveRange(exchange.getResponseSender(), exchange, start, end, IoCallback.END_EXCHANGE);
} else {
resource.serve(exchange.getResponseSender(), exchange, IoCallback.END_EXCHANGE);
}
}
};
if (exchange.isInIoThread()) {
exchange.dispatch(dispatchTask);
} else {
dispatchTask.handleRequest(exchange);
}
}
Aggregations