diff --git a/Plan/dependency-reduced-pom.xml b/Plan/dependency-reduced-pom.xml index 617d9d013..4441b3970 100644 --- a/Plan/dependency-reduced-pom.xml +++ b/Plan/dependency-reduced-pom.xml @@ -20,6 +20,7 @@ **/*.js **/*.css locale/*.txt + **/*.ico diff --git a/Plan/pom.xml b/Plan/pom.xml index 29e3b0339..09de51fe9 100644 --- a/Plan/pom.xml +++ b/Plan/pom.xml @@ -223,6 +223,7 @@ **/*.js **/*.css locale/*.txt + **/*.ico diff --git a/Plan/src/main/java/com/djrapitops/plan/system/file/PlanFiles.java b/Plan/src/main/java/com/djrapitops/plan/system/file/PlanFiles.java index 748f6fc56..61e7b4e7d 100644 --- a/Plan/src/main/java/com/djrapitops/plan/system/file/PlanFiles.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/file/PlanFiles.java @@ -14,6 +14,7 @@ import javax.inject.Inject; import javax.inject.Singleton; import java.io.File; import java.io.IOException; +import java.io.InputStream; import java.util.List; /** @@ -110,6 +111,10 @@ public class PlanFiles implements SubSystem { )); } + public InputStream readCustomizableResource(String fileName) { + return FileUtil.stream(plugin, new File(plugin.getDataFolder(), fileName.replace("/", File.separator)), fileName); + } + private String flatten(List lines) { StringBuilder flat = new StringBuilder(); for (String line : lines) { diff --git a/Plan/src/main/java/com/djrapitops/plan/system/webserver/ResponseHandler.java b/Plan/src/main/java/com/djrapitops/plan/system/webserver/ResponseHandler.java index 340e42e6d..6c1fb0be3 100644 --- a/Plan/src/main/java/com/djrapitops/plan/system/webserver/ResponseHandler.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/webserver/ResponseHandler.java @@ -66,7 +66,6 @@ public class ResponseHandler extends TreePageHandler { } public void registerPages() { - registerPage("favicon.ico", responseFactory.redirectResponse("https://puu.sh/tK0KL/6aa2ba141b.ico"), 5); registerPage("debug", debugPageHandler); registerPage("players", playersPageHandler); registerPage("player", playerPageHandler); @@ -124,6 +123,9 @@ public class ResponseHandler extends TreePageHandler { if (targetString.endsWith(".js")) { return ResponseCache.loadResponse(PageId.JS.of(targetString), () -> responseFactory.javaScriptResponse(targetString)); } + if (targetString.endsWith("favicon.ico")) { + return ResponseCache.loadResponse(PageId.FAVICON.id(), responseFactory::faviconResponse); + } boolean isNotInfoRequest = target.isEmpty() || !target.get(0).equals("info"); boolean isAuthRequired = webServer.get().isAuthRequired() && isNotInfoRequest; if (isAuthRequired) { diff --git a/Plan/src/main/java/com/djrapitops/plan/system/webserver/cache/PageId.java b/Plan/src/main/java/com/djrapitops/plan/system/webserver/cache/PageId.java index 7aa38dd38..e00924ebe 100644 --- a/Plan/src/main/java/com/djrapitops/plan/system/webserver/cache/PageId.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/webserver/cache/PageId.java @@ -26,7 +26,7 @@ public enum PageId { JS("js:"), CSS("css:"), - FAVICON_REDIRECT("Redirect:Favicon"), + FAVICON("Favicon"), PLAYER_PLUGINS_TAB("playerPluginsTab:"), NETWORK_CONTENT("networkContent"); diff --git a/Plan/src/main/java/com/djrapitops/plan/system/webserver/response/ByteResponse.java b/Plan/src/main/java/com/djrapitops/plan/system/webserver/response/ByteResponse.java new file mode 100644 index 000000000..b5b7501ba --- /dev/null +++ b/Plan/src/main/java/com/djrapitops/plan/system/webserver/response/ByteResponse.java @@ -0,0 +1,44 @@ +package com.djrapitops.plan.system.webserver.response; + +import com.djrapitops.plan.system.file.PlanFiles; +import com.djrapitops.plan.system.locale.Locale; +import com.djrapitops.plan.system.settings.theme.Theme; +import com.sun.net.httpserver.HttpExchange; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +/** + * {@link Response} for raw bytes. + * + * @author Rsl1122 + */ +public class ByteResponse extends Response { + + private final PlanFiles files; + private final String fileName; + + public ByteResponse(ResponseType type, String fileName, PlanFiles files) { + super(type); + this.fileName = fileName; + this.files = files; + + setHeader("HTTP/1.1 200 OK"); + } + + @Override + public void send(HttpExchange exchange, Locale locale, Theme theme) throws IOException { + responseHeaders.set("Accept-Ranges", "bytes"); + exchange.sendResponseHeaders(getCode(), 0); + + try (OutputStream out = exchange.getResponseBody(); + InputStream bis = files.readCustomizableResource(fileName)) { + byte[] buffer = new byte[2048]; + int count; + while ((count = bis.read(buffer)) != -1) { + out.write(buffer, 0, count); + } + } + } +} diff --git a/Plan/src/main/java/com/djrapitops/plan/system/webserver/response/ResponseFactory.java b/Plan/src/main/java/com/djrapitops/plan/system/webserver/response/ResponseFactory.java index 729019d30..9e9137b8e 100644 --- a/Plan/src/main/java/com/djrapitops/plan/system/webserver/response/ResponseFactory.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/webserver/response/ResponseFactory.java @@ -115,6 +115,10 @@ public class ResponseFactory { return new RedirectResponse(location); } + public Response faviconResponse() { + return new ByteResponse(ResponseType.X_ICON, "web/favicon.ico", files); + } + public ErrorResponse pageNotFound404() { return notFound404(locale.getString(ErrorPageLang.UNKNOWN_PAGE_404)); } diff --git a/Plan/src/main/java/com/djrapitops/plan/system/webserver/response/ResponseType.java b/Plan/src/main/java/com/djrapitops/plan/system/webserver/response/ResponseType.java index 85ea8b115..85a1f0799 100644 --- a/Plan/src/main/java/com/djrapitops/plan/system/webserver/response/ResponseType.java +++ b/Plan/src/main/java/com/djrapitops/plan/system/webserver/response/ResponseType.java @@ -13,7 +13,9 @@ public enum ResponseType { HTML("text/html; charset=utf-8"), CSS("text/css"), JSON("application/json"), - JAVASCRIPT("application/javascript"); + JAVASCRIPT("application/javascript"), + IMAGE("image/gif"), + X_ICON("image/x-icon"); private final String type; diff --git a/Plan/src/main/java/com/djrapitops/plan/utilities/file/FileUtil.java b/Plan/src/main/java/com/djrapitops/plan/utilities/file/FileUtil.java index 3d6cd366e..e50f5c684 100644 --- a/Plan/src/main/java/com/djrapitops/plan/utilities/file/FileUtil.java +++ b/Plan/src/main/java/com/djrapitops/plan/utilities/file/FileUtil.java @@ -4,10 +4,7 @@ import com.djrapitops.plan.PlanPlugin; import com.djrapitops.plan.utilities.MiscUtils; import com.djrapitops.plugin.logging.L; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; +import java.io.*; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.nio.file.Files; @@ -34,6 +31,31 @@ public class FileUtil { return lines(plugin, defaults); } + public static InputStream stream(PlanPlugin plugin, File savedFile, String defaults) { + try { + if (savedFile.exists()) { + return stream(savedFile); + } else { + String fileName = savedFile.getName(); + File found = attemptToFind(fileName, new File(plugin.getDataFolder(), "web")); + if (found != null) { + return stream(found); + } + } + } catch (FileNotFoundException ignore) { + // File was not found, use jar version + } + return stream(plugin, defaults); + } + + private static InputStream stream(PlanPlugin plugin, String resource) { + return plugin.getResource(resource); + } + + private static InputStream stream(File savedFile) throws FileNotFoundException { + return new FileInputStream(savedFile); + } + /** * Breadth-First search through the file tree to find the file. * diff --git a/Plan/src/main/resources/web/favicon.ico b/Plan/src/main/resources/web/favicon.ico new file mode 100644 index 000000000..cea02dd44 Binary files /dev/null and b/Plan/src/main/resources/web/favicon.ico differ