From 46a65781246032dc62160c30cf50babb8dd6288c Mon Sep 17 00:00:00 2001 From: JFronny <33260128+JFronny@users.noreply.github.com> Date: Wed, 23 Sep 2020 20:22:36 +0200 Subject: [PATCH] Migrate to LibWeb --- build.gradle | 13 +- gradle.properties | 9 +- .../java/io/gitlab/jfronny/dynres/Cfg.java | 9 - .../java/io/gitlab/jfronny/dynres/DynRes.java | 107 ++------ .../mixin/ServerPropertiesHandlerMixin.java | 5 +- .../jfronny/dynres/web/RequestHandler.java | 53 ---- .../web/bluemapcore/HttpConnection.java | 127 --------- .../dynres/web/bluemapcore/HttpRequest.java | 245 ------------------ .../web/bluemapcore/HttpRequestHandler.java | 34 --- .../dynres/web/bluemapcore/HttpResponse.java | 155 ----------- .../web/bluemapcore/HttpStatusCode.java | 70 ----- .../dynres/web/bluemapcore/WebServer.java | 126 --------- src/main/resources/fabric.mod.json | 5 +- 13 files changed, 40 insertions(+), 918 deletions(-) delete mode 100644 src/main/java/io/gitlab/jfronny/dynres/web/RequestHandler.java delete mode 100644 src/main/java/io/gitlab/jfronny/dynres/web/bluemapcore/HttpConnection.java delete mode 100644 src/main/java/io/gitlab/jfronny/dynres/web/bluemapcore/HttpRequest.java delete mode 100644 src/main/java/io/gitlab/jfronny/dynres/web/bluemapcore/HttpRequestHandler.java delete mode 100644 src/main/java/io/gitlab/jfronny/dynres/web/bluemapcore/HttpResponse.java delete mode 100644 src/main/java/io/gitlab/jfronny/dynres/web/bluemapcore/HttpStatusCode.java delete mode 100644 src/main/java/io/gitlab/jfronny/dynres/web/bluemapcore/WebServer.java diff --git a/build.gradle b/build.gradle index 2437eb3..a2317ee 100644 --- a/build.gradle +++ b/build.gradle @@ -3,6 +3,10 @@ plugins { id 'maven-publish' } +repositories { + maven { url 'https://jitpack.io' } +} + sourceCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8 @@ -16,12 +20,19 @@ dependencies { mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" - modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" + modImplementation "net.fabricmc.fabric-api:fabric-command-api-v1:+" + modImplementation "net.fabricmc.fabric-api:fabric-lifecycle-events-v1:+" + modImplementation "net.fabricmc.fabric-api:fabric-api-base:+" modApi("me.sargunvohra.mcmods:autoconfig1u:3.2.2") { exclude(group: "net.fabricmc.fabric-api") } include "me.sargunvohra.mcmods:autoconfig1u:3.2.2" + + modImplementation ('com.gitlab.JFronny:LibWeb:-SNAPSHOT') { + exclude(group: "net.fabricmc.fabric-api") + } + include "com.gitlab.JFronny:LibWeb:-SNAPSHOT" } processResources { diff --git a/gradle.properties b/gradle.properties index 6abfaa5..23845ac 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,13 +2,10 @@ org.gradle.jvmargs=-Xmx1G # Fabric Properties # check these on https://modmuss50.me/fabric.html -minecraft_version=1.16.2 -yarn_mappings=1.16.2+build.47 +minecraft_version=1.16.3 +yarn_mappings=1.16.3+build.11 loader_version=0.9.3+build.207 # Mod Properties -mod_version=1.0 +mod_version=1.1 maven_group=io.gitlab.jfronny archives_base_name=dynres -# Dependencies -# check this on https://modmuss50.me/fabric.html -fabric_version=0.20.1+build.401-1.16 diff --git a/src/main/java/io/gitlab/jfronny/dynres/Cfg.java b/src/main/java/io/gitlab/jfronny/dynres/Cfg.java index bf04b14..2b081d1 100644 --- a/src/main/java/io/gitlab/jfronny/dynres/Cfg.java +++ b/src/main/java/io/gitlab/jfronny/dynres/Cfg.java @@ -6,15 +6,6 @@ import me.sargunvohra.mcmods.autoconfig1u.shadowed.blue.endless.jankson.Comment; @Config(name = "dynres") public class Cfg implements ConfigData { - @Comment("The base of the link to send to client. This is equal to the address for clients to enter (requires a restart)") - public String baseLink = "http://127.0.0.1"; - - @Comment("The port to use for hosting the file. Use 0 for a random one (requires a restart)") - public int port = 0; - - @Comment("The number of allowed concurrent downloads. Higher values prevent errors on clients but can increase load") - public int maxConnections = 20; - @Comment("The relative path to the resources zip. Expect strange behaviour if changed") public String resourcesFile = "resources.zip"; diff --git a/src/main/java/io/gitlab/jfronny/dynres/DynRes.java b/src/main/java/io/gitlab/jfronny/dynres/DynRes.java index 07e93f5..9116fdd 100644 --- a/src/main/java/io/gitlab/jfronny/dynres/DynRes.java +++ b/src/main/java/io/gitlab/jfronny/dynres/DynRes.java @@ -1,110 +1,43 @@ package io.gitlab.jfronny.dynres; -import com.mojang.brigadier.Command; -import io.gitlab.jfronny.dynres.web.RequestHandler; -import io.gitlab.jfronny.dynres.web.bluemapcore.WebServer; +import io.gitlab.jfronny.libweb.api.LibWebAPI; +import io.gitlab.jfronny.libweb.api.LibWebInit; import me.sargunvohra.mcmods.autoconfig1u.AutoConfig; import me.sargunvohra.mcmods.autoconfig1u.serializer.JanksonConfigSerializer; import net.fabricmc.api.DedicatedServerModInitializer; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; -import net.fabricmc.fabric.api.command.v1.CommandRegistrationCallback; -import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; import net.fabricmc.loader.api.FabricLoader; import net.fabricmc.loader.gui.FabricGuiEntry; -import net.minecraft.server.command.CommandManager; -import net.minecraft.text.LiteralText; import java.io.File; import java.io.FileNotFoundException; -import java.util.Arrays; +import java.io.IOException; -@Environment(EnvType.SERVER) -public class DynRes implements DedicatedServerModInitializer { - static WebServer server; +public class DynRes implements LibWebInit { public static File resFile; public static Cfg cfg; - - static { - AutoConfig.register(Cfg.class, JanksonConfigSerializer::new); - cfg = AutoConfig.getConfigHolder(Cfg.class).getConfig(); - resFile = new File(FabricLoader.getInstance().getGameDir().toFile(), cfg.resourcesFile); - if (!resFile.isFile()) { - FabricGuiEntry.displayCriticalError(new FileNotFoundException("The file " + resFile + " does not exist in the game directory but is required"), true); - } - } + public static String resourceLink = ""; + private static boolean initialized = false; @Override - public void onInitializeServer() { - ServerLifecycleEvents.SERVER_STOPPED.register(t -> { + public void register(LibWebAPI api) { + if (FabricLoader.getInstance().getEnvironmentType() == EnvType.SERVER) { try { - server.close(); - server.join(); - } catch (Throwable e) { - Logger.l.error("Failed to stop web server", e); - } - }); - - CommandRegistrationCallback.EVENT.register((dispatcher, dedicated) -> { - if (dedicated) { - dispatcher.register(CommandManager.literal("dynres").requires((serverCommandSource) -> serverCommandSource.hasPermissionLevel(4)) - .executes(context -> { - context.getSource().sendFeedback(new LiteralText("DynRes is active. Use dynres restart to reload"), false); - return Command.SINGLE_SUCCESS; - })); - dispatcher.register(CommandManager.literal("dynres").requires((serverCommandSource) -> serverCommandSource.hasPermissionLevel(4)) - .then(CommandManager.literal("restart").executes(context -> { - try { - context.getSource().sendFeedback(new LiteralText("Restarting DynRes"), true); - cfg = AutoConfig.getConfigHolder(Cfg.class).getConfig(); - resFile = new File(FabricLoader.getInstance().getGameDir().toFile(), cfg.resourcesFile); - restartServer(); + if (!initialized) { + initialized = true; + AutoConfig.register(Cfg.class, JanksonConfigSerializer::new); + cfg = AutoConfig.getConfigHolder(Cfg.class).getConfig(); + resFile = new File(FabricLoader.getInstance().getGameDir().toFile(), cfg.resourcesFile); + if (!resFile.isFile()) { + FabricGuiEntry.displayCriticalError(new FileNotFoundException("The file " + resFile + " does not exist in the game directory but is required"), true); } - catch (Exception e) { - Logger.l.error("Failed to run restart command", e); - context.getSource().sendError(new LiteralText(e.getMessage())); - } - return Command.SINGLE_SUCCESS; - }))); - } - else { - Logger.l.error("DYNRES SHOULD NOT BE RUN ON INTERNAL SERVERS!"); - } - }); - - restartServer(); - } - - public static void restartServer() { - int port = cfg.port; - if (server != null) { - port = server.getPort(); - server.close(); - try { - server.join(); - } catch (InterruptedException e) { - //It is most likely already dead + Logger.l.info("Initialized DynRes"); + } + resourceLink = api.registerFile("/resources.zip", resFile.toPath(), !cfg.hashResources); + } catch (IOException e) { + e.printStackTrace(); } } - server = new WebServer(port, cfg.maxConnections, null, new RequestHandler("resources.zip")); - server.start(); - } - - public static String getPort() { - return Integer.toString(server.getPort()); - } - - public static String simplifyElement(String s) { - String path = s.toLowerCase(); - if (path.startsWith("/")) path = path.substring(1); - if (path.endsWith("/")) path = path.substring(0, path.length() - 1); - return path; - } - - public static String removePort(String s) { - String[] r = s.split(":"); - if (r.length > 2) - r = Arrays.copyOf(r, 2); - return String.join(":", r); } } diff --git a/src/main/java/io/gitlab/jfronny/dynres/mixin/ServerPropertiesHandlerMixin.java b/src/main/java/io/gitlab/jfronny/dynres/mixin/ServerPropertiesHandlerMixin.java index 35fdbc0..6c290b7 100644 --- a/src/main/java/io/gitlab/jfronny/dynres/mixin/ServerPropertiesHandlerMixin.java +++ b/src/main/java/io/gitlab/jfronny/dynres/mixin/ServerPropertiesHandlerMixin.java @@ -3,6 +3,8 @@ package io.gitlab.jfronny.dynres.mixin; import io.gitlab.jfronny.dynres.DynRes; import io.gitlab.jfronny.dynres.Logger; import io.gitlab.jfronny.dynres.ServerPropertiesHandlerExt; +import io.gitlab.jfronny.libweb.extra.LibWeb; +import io.gitlab.jfronny.libweb.extra.WebPaths; import net.minecraft.server.dedicated.ServerPropertiesHandler; import net.minecraft.util.registry.DynamicRegistryManager; import org.apache.commons.codec.digest.DigestUtils; @@ -14,7 +16,6 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import java.io.FileInputStream; import java.io.IOException; -import java.util.Objects; import java.util.Properties; @Mixin(ServerPropertiesHandler.class) @@ -32,7 +33,7 @@ public class ServerPropertiesHandlerMixin implements ServerPropertiesHandlerExt @Override public void applyChanges(boolean print) { - resourcePack = DynRes.removePort(DynRes.simplifyElement(DynRes.cfg.baseLink)) + ":" + DynRes.getPort() + "/resources.zip"; + resourcePack = WebPaths.concat(LibWeb.api.getServerRoot(), "resources.zip"); if (print) Logger.l.info("Pack link: " + resourcePack); resourcePackSha1 = ""; diff --git a/src/main/java/io/gitlab/jfronny/dynres/web/RequestHandler.java b/src/main/java/io/gitlab/jfronny/dynres/web/RequestHandler.java deleted file mode 100644 index f867454..0000000 --- a/src/main/java/io/gitlab/jfronny/dynres/web/RequestHandler.java +++ /dev/null @@ -1,53 +0,0 @@ -package io.gitlab.jfronny.dynres.web; - -import io.gitlab.jfronny.dynres.DynRes; -import io.gitlab.jfronny.dynres.Logger; -import io.gitlab.jfronny.dynres.web.bluemapcore.HttpRequest; -import io.gitlab.jfronny.dynres.web.bluemapcore.HttpRequestHandler; -import io.gitlab.jfronny.dynres.web.bluemapcore.HttpResponse; -import io.gitlab.jfronny.dynres.web.bluemapcore.HttpStatusCode; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.util.Objects; - -public class RequestHandler implements HttpRequestHandler { - String r; - @Override - public HttpResponse handle(HttpRequest request) { - try { - //TODO remove debug statement - Logger.l.info("Got connection"); - String method = request.getMethod().toUpperCase(); - if (!method.equals("GET") && !method.equals("HEAD") && !method.equals("POST")) { - Logger.l.error("Invalid method: " + method); - HttpResponse resp = new HttpResponse(HttpStatusCode.BAD_REQUEST); - resp.setData(method + " method not supported"); - return resp; - } - - String path = DynRes.simplifyElement(request.getPath()); - - if (Objects.equals(path, r)) { - HttpResponse resp = new HttpResponse(HttpStatusCode.OK); - resp.addHeader("Server", "DynRes using BlueMap"); - resp.addHeader("Cache-Control", "no-cache"); - resp.addHeader("Content-Type", "application/zip"); - - FileInputStream fs = new FileInputStream(DynRes.resFile); - resp.setData(fs); - return resp; - } - Logger.l.error("An invalid file was requested: " + path); - return new HttpResponse(HttpStatusCode.NOT_FOUND); - } catch (Throwable e) { - Logger.l.error("Cough error while sending", e); - return new HttpResponse(HttpStatusCode.INTERNAL_SERVER_ERROR); - } - } - - public RequestHandler(String relativePath) { - r = relativePath; - } -} diff --git a/src/main/java/io/gitlab/jfronny/dynres/web/bluemapcore/HttpConnection.java b/src/main/java/io/gitlab/jfronny/dynres/web/bluemapcore/HttpConnection.java deleted file mode 100644 index 32abd47..0000000 --- a/src/main/java/io/gitlab/jfronny/dynres/web/bluemapcore/HttpConnection.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * This file is part of BlueMap, licensed under the MIT License (MIT). - * - * Copyright (c) Blue (Lukas Rieger) - * Copyright (c) contributors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package io.gitlab.jfronny.dynres.web.bluemapcore; - -import io.gitlab.jfronny.dynres.DynRes; -import io.gitlab.jfronny.dynres.Logger; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.ServerSocket; -import java.net.Socket; -import java.net.SocketException; -import java.net.SocketTimeoutException; -import java.util.concurrent.TimeUnit; - -public class HttpConnection implements Runnable { - - private HttpRequestHandler handler; - - private ServerSocket server; - private Socket connection; - private InputStream in; - private OutputStream out; - - public HttpConnection(ServerSocket server, Socket connection, HttpRequestHandler handler, int timeout, TimeUnit timeoutUnit) throws IOException { - this.server = server; - this.connection = connection; - this.handler = handler; - - if (isClosed()){ - throw new IOException("Socket already closed!"); - } - - connection.setSoTimeout((int) timeoutUnit.toMillis(timeout)); - - in = this.connection.getInputStream(); - out = this.connection.getOutputStream(); - } - - @Override - public void run() { - while (!isClosed() && !server.isClosed()){ - try { - HttpRequest request = acceptRequest(); - HttpResponse response = handler.handle(request); - sendResponse(response); - } catch (InvalidRequestException e){ - try { - sendResponse(new HttpResponse(HttpStatusCode.BAD_REQUEST)); - } catch (IOException e1) {} - break; - } catch (SocketTimeoutException e) { - break; - } catch (SocketException e){ - break; - } catch (ConnectionClosedException e){ - break; - } catch (IOException e) { - Logger.l.error("Unexpected error while processing a HttpRequest!", e); - break; - } - } - - try { - close(); - } catch (IOException e){ - Logger.l.error("Error while closing HttpConnection!", e); - } - } - - private void sendResponse(HttpResponse response) throws IOException { - response.write(out); - out.flush(); - } - - private HttpRequest acceptRequest() throws ConnectionClosedException, InvalidRequestException, IOException { - return HttpRequest.read(in); - } - - public boolean isClosed(){ - return !connection.isBound() || connection.isClosed() || !connection.isConnected() || connection.isOutputShutdown() || connection.isInputShutdown(); - } - - public void close() throws IOException { - try { - in.close(); - } finally { - try { - out.close(); - } finally { - connection.close(); - } - } - } - - public static class ConnectionClosedException extends IOException { - private static final long serialVersionUID = 1L; - } - - public static class InvalidRequestException extends IOException { - private static final long serialVersionUID = 1L; - } - -} diff --git a/src/main/java/io/gitlab/jfronny/dynres/web/bluemapcore/HttpRequest.java b/src/main/java/io/gitlab/jfronny/dynres/web/bluemapcore/HttpRequest.java deleted file mode 100644 index 1306161..0000000 --- a/src/main/java/io/gitlab/jfronny/dynres/web/bluemapcore/HttpRequest.java +++ /dev/null @@ -1,245 +0,0 @@ -/* - * This file is part of BlueMap, licensed under the MIT License (MIT). - * - * Copyright (c) Blue (Lukas Rieger) - * Copyright (c) contributors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package io.gitlab.jfronny.dynres.web.bluemapcore; - -import java.io.BufferedReader; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import io.gitlab.jfronny.dynres.web.bluemapcore.HttpConnection.ConnectionClosedException; -import io.gitlab.jfronny.dynres.web.bluemapcore.HttpConnection.InvalidRequestException; - -public class HttpRequest { - - private static final Pattern REQUEST_PATTERN = Pattern.compile("^(\\w+) (\\S+) (.+)$"); - - private String method; - private String adress; - private String version; - private Map> header; - private Map> headerLC; - private byte[] data; - - private String path = null; - private Map getParams = null; - private String getParamString = null; - - public HttpRequest(String method, String adress, String version, Map> header) { - this.method = method; - this.adress = adress; - this.version = version; - this.header = header; - this.headerLC = new HashMap<>(); - - for (Entry> e : header.entrySet()){ - Set values = new HashSet<>(); - for (String v : e.getValue()){ - values.add(v.toLowerCase()); - } - - headerLC.put(e.getKey().toLowerCase(), values); - } - - this.data = new byte[0]; - } - - public String getMethod() { - return method; - } - - public String getAdress(){ - return adress; - } - - public String getVersion() { - return version; - } - - public Map> getHeader() { - return header; - } - - public Map> getLowercaseHeader() { - return headerLC; - } - - public Set getHeader(String key){ - Set headerValues = header.get(key); - if (headerValues == null) return Collections.emptySet(); - return headerValues; - } - - public Set getLowercaseHeader(String key){ - Set headerValues = headerLC.get(key.toLowerCase()); - if (headerValues == null) return Collections.emptySet(); - return headerValues; - } - - public String getPath() { - if (path == null) parseAdress(); - return path; - } - - public Map getGETParams() { - if (getParams == null) parseAdress(); - return Collections.unmodifiableMap(getParams); - } - - public String getGETParamString() { - if (getParamString == null) parseAdress(); - return getParamString; - } - - private void parseAdress() { - String adress = this.adress; - if (adress.isEmpty()) adress = "/"; - String[] adressParts = adress.split("\\?", 2); - String path = adressParts[0]; - this.getParamString = adressParts.length > 1 ? adressParts[1] : ""; - - Map getParams = new HashMap<>(); - for (String getParam : this.getParamString.split("&")){ - if (getParam.isEmpty()) continue; - String[] kv = getParam.split("=", 2); - String key = kv[0]; - String value = kv.length > 1 ? kv[1] : ""; - getParams.put(key, value); - } - - this.path = path; - this.getParams = getParams; - } - - public InputStream getData(){ - return new ByteArrayInputStream(data); - } - - public static HttpRequest read(InputStream in) throws IOException, InvalidRequestException { - BufferedReader reader = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8)); - List header = new ArrayList<>(20); - while(header.size() < 1000){ - String headerLine = readLine(reader); - if (headerLine.isEmpty()) break; - header.add(headerLine); - } - - if (header.isEmpty()) throw new InvalidRequestException(); - - Matcher m = REQUEST_PATTERN.matcher(header.remove(0)); - if (!m.find()) throw new InvalidRequestException(); - - String method = m.group(1); - if (method == null) throw new InvalidRequestException(); - - String adress = m.group(2); - if (adress == null) throw new InvalidRequestException(); - - String version = m.group(3); - if (version == null) throw new InvalidRequestException(); - - Map> headerMap = new HashMap>(); - for (String line : header){ - if (line.trim().isEmpty()) continue; - - String[] kv = line.split(":", 2); - if (kv.length < 2) continue; - - Set values = new HashSet<>(); - if (kv[0].trim().equalsIgnoreCase("If-Modified-Since")){ - values.add(kv[1].trim()); - } else { - for(String v : kv[1].split(",")){ - values.add(v.trim()); - } - } - - headerMap.put(kv[0].trim(), values); - } - - HttpRequest request = new HttpRequest(method, adress, version, headerMap); - - if (request.getLowercaseHeader("Transfer-Encoding").contains("chunked")){ - try { - ByteArrayOutputStream dataStream = new ByteArrayOutputStream(); - while (dataStream.size() < 1000000){ - String hexSize = reader.readLine(); - int chunkSize = Integer.parseInt(hexSize, 16); - if (chunkSize <= 0) break; - byte[] data = new byte[chunkSize]; - in.read(data); - dataStream.write(data); - } - - if (dataStream.size() >= 1000000) { - throw new InvalidRequestException(); - } - - request.data = dataStream.toByteArray(); - - return request; - } catch (NumberFormatException ex){ - return request; - } - } else { - Set clSet = request.getLowercaseHeader("Content-Length"); - if (clSet.isEmpty()){ - return request; - } else { - try { - int cl = Integer.parseInt(clSet.iterator().next()); - byte[] data = new byte[cl]; - in.read(data); - request.data = data; - return request; - } catch (NumberFormatException ex){ - return request; - } - } - } - } - - private static String readLine(BufferedReader in) throws ConnectionClosedException, IOException { - String line = in.readLine(); - if (line == null){ - throw new ConnectionClosedException(); - } - return line; - } - -} diff --git a/src/main/java/io/gitlab/jfronny/dynres/web/bluemapcore/HttpRequestHandler.java b/src/main/java/io/gitlab/jfronny/dynres/web/bluemapcore/HttpRequestHandler.java deleted file mode 100644 index 84a73ad..0000000 --- a/src/main/java/io/gitlab/jfronny/dynres/web/bluemapcore/HttpRequestHandler.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * This file is part of BlueMap, licensed under the MIT License (MIT). - * - * Copyright (c) Blue (Lukas Rieger) - * Copyright (c) contributors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package io.gitlab.jfronny.dynres.web.bluemapcore; - -import org.apache.http.MethodNotSupportedException; - -@FunctionalInterface -public interface HttpRequestHandler { - - HttpResponse handle(HttpRequest request); - -} diff --git a/src/main/java/io/gitlab/jfronny/dynres/web/bluemapcore/HttpResponse.java b/src/main/java/io/gitlab/jfronny/dynres/web/bluemapcore/HttpResponse.java deleted file mode 100644 index 6da43ad..0000000 --- a/src/main/java/io/gitlab/jfronny/dynres/web/bluemapcore/HttpResponse.java +++ /dev/null @@ -1,155 +0,0 @@ -/* - * This file is part of BlueMap, licensed under the MIT License (MIT). - * - * Copyright (c) Blue (Lukas Rieger) - * Copyright (c) contributors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package io.gitlab.jfronny.dynres.web.bluemapcore; - -import java.io.ByteArrayInputStream; -import java.io.Closeable; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.nio.charset.StandardCharsets; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -import org.apache.commons.lang3.StringUtils; - -public class HttpResponse implements Closeable { - - private String version; - private HttpStatusCode statusCode; - private Map> header; - private InputStream data; - - public HttpResponse(HttpStatusCode statusCode) { - this.version = "HTTP/1.1"; - this.statusCode = statusCode; - - this.header = new HashMap<>(); - - addHeader("Connection", "keep-alive"); - } - - public void addHeader(String key, String value){ - Set valueSet = header.get(key); - if (valueSet == null){ - valueSet = new HashSet<>(); - header.put(key, valueSet); - } - - valueSet.add(value); - } - - public void removeHeader(String key, String value){ - Set valueSet = header.get(key); - if (valueSet == null){ - valueSet = new HashSet<>(); - header.put(key, valueSet); - } - - valueSet.remove(value); - } - - public void setData(InputStream dataStream){ - this.data = dataStream; - } - - public void setData(String data){ - setData(new ByteArrayInputStream(data.getBytes(StandardCharsets.UTF_8))); - } - - /** - * Writes this Response to an Output-Stream.
- *
- * This method closes the data-Stream of this response so it can't be used again! - */ - public void write(OutputStream out) throws IOException { - OutputStreamWriter writer = new OutputStreamWriter(out, StandardCharsets.UTF_8); - - if (data != null){ - addHeader("Transfer-Encoding", "chunked"); - } else { - addHeader("Content-Length", "0"); - } - - writeLine(writer, version + " " + statusCode.getCode() + " " + statusCode.getMessage()); - for (Entry> e : header.entrySet()){ - if (e.getValue().isEmpty()) continue; - writeLine(writer, e.getKey() + ": " + StringUtils.join(e.getValue(), ", ")); - } - - writeLine(writer, ""); - writer.flush(); - - if(data != null){ - chunkedPipe(data, out); - out.flush(); - data.close(); - } - } - - @Override - public void close() throws IOException { - data.close(); - } - - private void writeLine(OutputStreamWriter writer, String line) throws IOException { - writer.write(line + "\r\n"); - } - - private void chunkedPipe(InputStream input, OutputStream output) throws IOException { - byte[] buffer = new byte[1024]; - int byteCount; - while ((byteCount = input.read(buffer)) != -1) { - output.write((Integer.toHexString(byteCount) + "\r\n").getBytes()); - output.write(buffer, 0, byteCount); - output.write("\r\n".getBytes()); - } - output.write("0\r\n\r\n".getBytes()); - } - - public HttpStatusCode getStatusCode(){ - return statusCode; - } - - public String getVersion(){ - return version; - } - - public Map> getHeader() { - return header; - } - - public Set getHeader(String key){ - Set headerValues = header.get(key); - if (headerValues == null) return Collections.emptySet(); - return headerValues; - } - -} diff --git a/src/main/java/io/gitlab/jfronny/dynres/web/bluemapcore/HttpStatusCode.java b/src/main/java/io/gitlab/jfronny/dynres/web/bluemapcore/HttpStatusCode.java deleted file mode 100644 index 0313946..0000000 --- a/src/main/java/io/gitlab/jfronny/dynres/web/bluemapcore/HttpStatusCode.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * This file is part of BlueMap, licensed under the MIT License (MIT). - * - * Copyright (c) Blue (Lukas Rieger) - * Copyright (c) contributors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package io.gitlab.jfronny.dynres.web.bluemapcore; - -public enum HttpStatusCode { - - CONTINUE (100, "Continue"), - PROCESSING (102, "Processing"), - - OK (200, "OK"), - - MOVED_PERMANENTLY (301, "Moved Permanently"), - FOUND (302, "Found"), - SEE_OTHER (303, "See Other"), - NOT_MODIFIED (304, "Not Modified"), - - BAD_REQUEST (400, "Bad Request"), - UNAUTHORIZED (401, "Unauthorized"), - FORBIDDEN (403, "Forbidden"), - NOT_FOUND (404, "Not Found"), - - INTERNAL_SERVER_ERROR (500, "Internal Server Error"), - NOT_IMPLEMENTED (501, "Not Implemented"), - SERVICE_UNAVAILABLE (503, "Service Unavailable"), - HTTP_VERSION_NOT_SUPPORTED (505, "HTTP Version not supported"); - - private int code; - private String message; - - private HttpStatusCode(int code, String message) { - this.code = code; - this.message = message; - } - - public int getCode(){ - return code; - } - - public String getMessage(){ - return message; - } - - @Override - public String toString() { - return getCode() + " " + getMessage(); - } - -} diff --git a/src/main/java/io/gitlab/jfronny/dynres/web/bluemapcore/WebServer.java b/src/main/java/io/gitlab/jfronny/dynres/web/bluemapcore/WebServer.java deleted file mode 100644 index 7ba541b..0000000 --- a/src/main/java/io/gitlab/jfronny/dynres/web/bluemapcore/WebServer.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * This file is part of BlueMap, licensed under the MIT License (MIT). - * - * Copyright (c) Blue (Lukas Rieger) - * Copyright (c) contributors - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -package io.gitlab.jfronny.dynres.web.bluemapcore; - -import io.gitlab.jfronny.dynres.DynRes; -import io.gitlab.jfronny.dynres.Logger; - -import java.io.IOException; -import java.net.InetAddress; -import java.net.ServerSocket; -import java.net.Socket; -import java.net.SocketException; -import java.util.concurrent.LinkedBlockingQueue; -import java.util.concurrent.RejectedExecutionException; -import java.util.concurrent.ThreadPoolExecutor; -import java.util.concurrent.TimeUnit; - -public class WebServer extends Thread { - - private int port; - private int maxConnections; - private final InetAddress bindAdress; - - private HttpRequestHandler handler; - - private ThreadPoolExecutor connectionThreads; - - private ServerSocket server; - - public WebServer(int port, int maxConnections, InetAddress bindAdress, HttpRequestHandler handler) { - this.port = port; - this.maxConnections = maxConnections; - this.bindAdress = bindAdress; - - this.handler = handler; - - connectionThreads = null; - } - - @Override - public void run(){ - close(); - - connectionThreads = new ThreadPoolExecutor(maxConnections, maxConnections, 10, TimeUnit.SECONDS, new LinkedBlockingQueue<>()); - connectionThreads.allowCoreThreadTimeOut(true); - - try { - server = new ServerSocket(port, maxConnections, bindAdress); - server.setSoTimeout(0); - } catch (IOException e){ - Logger.l.error("Error while starting the WebServer!", e); - return; - } - - Logger.l.info("WebServer started."); - - while (!server.isClosed() && server.isBound()){ - - try { - Socket connection = server.accept(); - - try { - connectionThreads.execute(new HttpConnection(server, connection, handler, 10, TimeUnit.SECONDS)); - } catch (RejectedExecutionException e){ - connection.close(); - Logger.l.error("Dropped an incoming HttpConnection! (Too many connections?)"); - } - - } catch (SocketException e){ - // this mainly occurs if the socket got closed, so we ignore this error - } catch (IOException e){ - Logger.l.error("Error while creating a new HttpConnection!", e); - } - - } - - Logger.l.info("WebServer closed."); - } - - public int getPort() { - return server.getLocalPort(); - } - - public void setPort(int port) { - this.port = port; - } - - public void setMaxConnections(int maxConnections) { - this.maxConnections = maxConnections; - } - - public void close(){ - if (connectionThreads != null) connectionThreads.shutdown(); - - try { - if (server != null && !server.isClosed()){ - server.close(); - } - } catch (IOException e) { - Logger.l.error("Error while closing WebServer!", e); - } - } - -} diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 1d2d62b..2552e24 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -15,7 +15,7 @@ "icon": "assets/dynres/icon.png", "environment": "*", "entrypoints": { - "server": [ + "libweb": [ "io.gitlab.jfronny.dynres.DynRes" ], "client": [ @@ -27,7 +27,6 @@ ], "depends": { "fabricloader": ">=0.9.3+build.207", - "fabric": "*", - "minecraft": "1.16.2" + "minecraft": "1.16.3" } }