asset.pipeline.ratpack.internal.ProductionAssetHandler Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ratpack-asset-pipeline Show documentation
Show all versions of ratpack-asset-pipeline Show documentation
Provides asset-pipeline integration with the ratpack framework.
/*
* Copyright 2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package asset.pipeline.ratpack.internal;
import asset.pipeline.AssetPipelineConfigHolder;
import asset.pipeline.AssetPipelineResponseBuilder;
import asset.pipeline.ratpack.AssetAttributes;
import com.google.common.collect.Maps;
import io.netty.handler.codec.http.HttpHeaderNames;
import ratpack.handling.Context;
import ratpack.handling.Handler;
import ratpack.http.Response;
import ratpack.http.internal.HttpHeaderConstants;
import ratpack.func.Factory;
import ratpack.func.Action;
import ratpack.exec.Blocking;
import java.nio.file.Path;
import java.nio.file.Files;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Arrays;
import java.util.Optional;
import java.util.Map;
import java.util.Properties;
import static ratpack.registry.Registry.single;
public class ProductionAssetHandler implements Handler {
private static final String ASSET_BASE_PATH = "assets/";
@Override
public void handle(Context ctx) throws Exception {
final Properties manifest = AssetPipelineConfigHolder.manifest;
final AssetProperties props = ctx.get(AssetProperties.class);
final ProductionAssetCache fileCache = ctx.get(ProductionAssetCache.class);
Response response = ctx.getResponse();
final String manifestPath = manifest.getProperty(props.getPath(), props.getPath());
final Path asset = ctx.file(ASSET_BASE_PATH + manifestPath);
final AssetPipelineResponseBuilder responseBuilder = new AssetPipelineResponseBuilder(props.getPath(),ctx.getRequest().getHeaders().get(HttpHeaderNames.IF_NONE_MATCH));
//Is this in the attribute cache?
AssetAttributes attributeCache = fileCache.get(manifestPath);
if(attributeCache != null) {
if(attributeCache.exists()) {
response.contentTypeIfNotSet(props.getFormat());
if(responseBuilder.headers != null) {
for (Map.Entry cursor : responseBuilder.headers.entrySet()) {
response.getHeaders().set(cursor.getKey(), cursor.getValue());
}
}
if(responseBuilder.statusCode != null) {
response.status(responseBuilder.statusCode);
}
if(responseBuilder.statusCode == null || responseBuilder.statusCode != 304) {
if(acceptsGzip(ctx) && attributeCache.gzipExists()) {
Path gzipFile = ctx.file(ASSET_BASE_PATH + manifestPath + ".gz");
response.getHeaders().set("Content-Encoding","gzip");
response.getHeaders().set(HttpHeaderConstants.CONTENT_LENGTH, Long.toString(attributeCache.getGzipFileSize()));
response.sendFile(gzipFile);
} else {
response.getHeaders().set(HttpHeaderConstants.CONTENT_LENGTH, Long.toString(attributeCache.getFileSize()));
response.noCompress().sendFile(asset);
}
} else {
response.send();
}
} else if(attributeCache.isDirectory()) {
doIndexFileNext(ctx, props);
} else {
ctx.next();
}
} else {
readAttributes(asset, attributes -> {
if (attributes == null || !attributes.isRegularFile()) {
if(props.getIndexedPath() != null && attributes != null) {
fileCache.put(manifestPath,new AssetAttributes(false,false,true, null , null));
doIndexFileNext(ctx, props);
} else {
fileCache.put(manifestPath,new AssetAttributes(false,false,false, null , null));
ctx.next();
}
} else {
response.contentTypeIfNotSet(props.getFormat());
if(responseBuilder.headers != null) {
for (Map.Entry cursor : responseBuilder.headers.entrySet()) {
response.getHeaders().set(cursor.getKey(), cursor.getValue());
}
}
if(responseBuilder.statusCode != null) {
response.status(responseBuilder.statusCode);
}
if(responseBuilder.statusCode == null || responseBuilder.statusCode != 304) {
Path gzipFile = ctx.file(ASSET_BASE_PATH + manifestPath + ".gz");
if(acceptsGzip(ctx)) {
readAttributes(gzipFile, gzipAttributes -> {
if (gzipAttributes == null || !gzipAttributes.isRegularFile()) {
response.getHeaders().set(HttpHeaderConstants.CONTENT_LENGTH, Long.toString(attributes.size()));
fileCache.put(manifestPath,new AssetAttributes(true,false,false, attributes.size() , null));
response.noCompress().sendFile(asset);
} else {
response.getHeaders().set("Content-Encoding","gzip");
response.getHeaders().set(HttpHeaderConstants.CONTENT_LENGTH, Long.toString(gzipAttributes.size()));
fileCache.put(manifestPath,new AssetAttributes(true,true,false, attributes.size() , gzipAttributes.size()));
response.sendFile(gzipFile);
}
});
} else {
response.getHeaders().set(HttpHeaderConstants.CONTENT_LENGTH, Long.toString(attributes.size()));
response.noCompress().sendFile(asset);
readAttributes(gzipFile, gzipAttributes -> {
if (gzipAttributes == null || !gzipAttributes.isRegularFile()) {
fileCache.put(manifestPath,new AssetAttributes(true,false,false, attributes.size() , null));
} else {
fileCache.put(manifestPath,new AssetAttributes(true,true,false, attributes.size() , gzipAttributes.size()));
}
});
}
} else {
response.send();
}
}
});
}
}
private void doIndexFileNext(Context ctx, AssetProperties props) {
ctx.insert(single(new AssetProperties(props.getIndexedPath(), null, props.getFormat(), props.getEncoding(), null)), this);
}
private boolean acceptsGzip(Context ctx) {
String acceptsEncoding = ctx.getRequest().getHeaders().get(HttpHeaderNames.ACCEPT_ENCODING);
return acceptsEncoding != null && acceptsEncoding.indexOf("gzip") > -1;
}
public static void readAttributes(Path file, Action super BasicFileAttributes> then) throws Exception {
Blocking.get(getter(file)).then(then);
}
private static Factory getter(Path file) {
return () -> {
if (file != null && Files.exists(file)) {
return Files.readAttributes(file, BasicFileAttributes.class);
} else {
return null;
}
};
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy