/**
* Copyright 2011-2014 the original author or authors.
*/
package com.jetdrone.vertx.yoke.middleware;
import com.jetdrone.vertx.yoke.Middleware;
import com.jetdrone.vertx.yoke.Yoke;
import com.jetdrone.vertx.yoke.util.Utils;
import org.jetbrains.annotations.NotNull;
import io.vertx.core.Handler;
import io.vertx.core.buffer.Buffer;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
/**
* # Favicon
*
* By default serves the Yoke favicon, or the favicon located by the given ```path```.
*/
public class Favicon extends Middleware {
/**
* ## Icon
*
* Represents a favicon.ico file and related headers
*/
private class Icon {
/**
* Headers for the icon resource
*/
private final Map<String, String> headers;
/**
* Binary content of the icon file
*/
private final Buffer body;
/**
* Instantiate a new Icon
*
* @param buffer buffer containing the image data for this icon.
*/
private Icon(Buffer buffer) {
headers = new HashMap<>();
body = buffer;
headers.put("content-type", "image/x-icon");
headers.put("content-length", Integer.toString(buffer.length()));
try {
MessageDigest md = MessageDigest.getInstance("MD5");
headers.put("etag", "\"" + Base64.getEncoder().encodeToString(md.digest(buffer.getBytes())) + "\"");
} catch (NoSuchAlgorithmException e) {
// ignore
}
headers.put("cache-control", "public, max-age=" + (maxAge / 1000));
}
}
/**
* favicon cache
*/
private Icon icon;
/**
* Location of the icon in the file system
*/
private final String path;
/**
* Cache control for the resource
*/
private final long maxAge;
/**
* Create a new Favicon instance using a file in the file system and customizable cache period
*
* <pre>
* Yoke yoke = new Yoke(...);
* yoke.use(new Favicon("/icons/icon.ico", 1000));
* </pre>
*
* @param path
* @param maxAge
*/
public Favicon(final String path, final long maxAge) {
this.path = path;
this.maxAge = maxAge;
}
/**
* Create a new Favicon instance using a file in the file system and cache for 1 day.
*
* <pre>
* Yoke yoke = new Yoke(...);
* yoke.use(new Favicon("/icons/icon.ico"));
* </pre>
*
* @param path
*/
public Favicon(String path) {
this(path, 86400000);
}
/**
* Create a new Favicon instance using a the default icon and cache for 1 day.
*
* <pre>
* Yoke yoke = new Yoke(...);
* yoke.use(new Favicon());
* </pre>
*/
public Favicon() {
this(null);
}
/**
* Loads the icon from the file system once we get a reference to Vert.x
*
* @param yoke
* @param mount
*/
@Override
public Middleware init(@NotNull final Yoke yoke, @NotNull final String mount) {
try {
super.init(yoke, mount);
if (path == null) {
icon = new Icon(Utils.readResourceToBuffer(getClass(), "favicon.ico"));
} else {
icon = new Icon(fileSystem().readFileBlocking(path));
}
} catch (Exception e) {
throw new RuntimeException(e);
}
return this;
}
@Override
public void handle(@NotNull final YokeRequest request, @NotNull final Handler<Object> next) {
if ("/favicon.ico".equals(request.normalizedPath())) {
request.response().headers().setAll(icon.headers);
request.response().end(icon.body);
} else {
next.handle(null);
}
}
}