From 8d9deef4a6a41b60700ce2ba1f93b2ed71cd9481 Mon Sep 17 00:00:00 2001 From: Jonas_Jones <91549607+J-onasJones@users.noreply.github.com> Date: Sat, 4 Mar 2023 21:40:09 +0100 Subject: [PATCH] some fixes I assume --- build.gradle | 2 + libs/java-curl-1.2.2.jar | Bin 0 -> 42863 bytes .../jonasjones/mcwebserver/McWebserver.java | 43 +++-- ...lizeMixin.java => WebserverStopMixin.java} | 11 +- .../mcwebserver/web/HTTPServer.java | 180 +++++++++--------- .../mcwebserver/web/ServerHandler.java | 28 +-- src/main/resources/mcwebserver.mixins.json | 3 +- 7 files changed, 149 insertions(+), 118 deletions(-) create mode 100644 libs/java-curl-1.2.2.jar rename src/main/java/me/jonasjones/mcwebserver/mixin/{InitializeMixin.java => WebserverStopMixin.java} (58%) diff --git a/build.gradle b/build.gradle index 7a3be5d..f49b7c8 100644 --- a/build.gradle +++ b/build.gradle @@ -31,6 +31,8 @@ dependencies { // These are included in the Fabric API production distribution and allow you to update your mod to the latest modules at a later more convenient time. // modImplementation "net.fabricmc.fabric-api:fabric-api-deprecated:${project.fabric_version}" + + implementation files('libs/java-curl-1.2.2.jar') } processResources { diff --git a/libs/java-curl-1.2.2.jar b/libs/java-curl-1.2.2.jar new file mode 100644 index 0000000000000000000000000000000000000000..3c20c7db43192580fdd30ab0143825b3f2b90fc4 GIT binary patch literal 42863 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 literal 0 HcmV?d00001 diff --git a/src/main/java/me/jonasjones/mcwebserver/McWebserver.java b/src/main/java/me/jonasjones/mcwebserver/McWebserver.java index 66b8327..9d5f394 100644 --- a/src/main/java/me/jonasjones/mcwebserver/McWebserver.java +++ b/src/main/java/me/jonasjones/mcwebserver/McWebserver.java @@ -1,12 +1,15 @@ package me.jonasjones.mcwebserver; +import com.roxstudio.utils.CUrl; import me.jonasjones.mcwebserver.config.ModConfigs; -import me.jonasjones.mcwebserver.web.HTTPServer; +import me.jonasjones.mcwebserver.web.ServerHandler; import net.fabricmc.api.ModInitializer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.net.Socket; +import java.util.concurrent.TimeUnit; + +import static me.jonasjones.mcwebserver.config.ModConfigs.WEB_PORT; public class McWebserver implements ModInitializer { // This logger is used to write text to the console and the log file. @@ -15,6 +18,9 @@ public class McWebserver implements ModInitializer { public static String MOD_ID = "mcwebserver"; public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID); public static final Logger VERBOSELOGGER = LoggerFactory.getLogger(MOD_ID + " - VERBOSE LOGGER"); + private static ServerHandler webserver = new ServerHandler(); + public static Thread webserverthread = new Thread(webserver); + public static boolean mcserveractive = true; @Override public void onInitialize() { @@ -24,15 +30,30 @@ public class McWebserver implements ModInitializer { LOGGER.info("McWebserver initialized!"); - if (ModConfigs.IS_ENABLED) { - LOGGER.info("Starting Webserver..."); - new Thread(() -> { - new HTTPServer(new Socket()); - HTTPServer.main(); - }).start(); - } else { - LOGGER.info("Webserver disabled in the config file."); - } + webserverthread.start(); + new Thread(() -> { + while (true) { + if (!mcserveractive) { + LOGGER.info("LMFAFMAKONJDGOADJINGOADNGHOADNHGOADNHOADHON"); + try { + TimeUnit.SECONDS.sleep(2); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + System.out.print("curl 127.0.0.1:" + WEB_PORT); + CUrl curl = new CUrl("curl http://localhost:" + WEB_PORT + "/index.html"); + curl.exec(); + break; + } else { + System.out.print(mcserveractive); + try { + TimeUnit.SECONDS.sleep(2); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + } + }).start(); } } diff --git a/src/main/java/me/jonasjones/mcwebserver/mixin/InitializeMixin.java b/src/main/java/me/jonasjones/mcwebserver/mixin/WebserverStopMixin.java similarity index 58% rename from src/main/java/me/jonasjones/mcwebserver/mixin/InitializeMixin.java rename to src/main/java/me/jonasjones/mcwebserver/mixin/WebserverStopMixin.java index 9212892..baeceaa 100644 --- a/src/main/java/me/jonasjones/mcwebserver/mixin/InitializeMixin.java +++ b/src/main/java/me/jonasjones/mcwebserver/mixin/WebserverStopMixin.java @@ -1,16 +1,17 @@ package me.jonasjones.mcwebserver.mixin; import me.jonasjones.mcwebserver.McWebserver; -import net.minecraft.client.gui.screen.TitleScreen; +import net.minecraft.server.MinecraftServer; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -@Mixin(TitleScreen.class) -public class InitializeMixin { - @Inject(at = @At("HEAD"), method = "init()V") +@Mixin(MinecraftServer.class) +public class WebserverStopMixin { + @Inject(at = @At("HEAD"), method = "shutdown") private void init(CallbackInfo info) { - McWebserver.LOGGER.info("This line is printed by an example mod mixin!"); + McWebserver.LOGGER.info("Stopping Webserver..."); + McWebserver.mcserveractive = false; } } diff --git a/src/main/java/me/jonasjones/mcwebserver/web/HTTPServer.java b/src/main/java/me/jonasjones/mcwebserver/web/HTTPServer.java index 0e2fc25..772576f 100644 --- a/src/main/java/me/jonasjones/mcwebserver/web/HTTPServer.java +++ b/src/main/java/me/jonasjones/mcwebserver/web/HTTPServer.java @@ -20,6 +20,8 @@ import java.nio.file.Path; import java.time.Instant; import java.util.StringTokenizer; +import static me.jonasjones.mcwebserver.McWebserver.mcserveractive; + public class HTTPServer implements Runnable { static Path WEB_ROOT; static final String DEFAULT_FILE = ModConfigs.WEB_FILE_ROOT; @@ -62,7 +64,7 @@ public class HTTPServer implements Runnable { McWebserver.LOGGER.info("Listening for connections on port : " + PORT); // we listen until user halts server execution - while (true) { + while (mcserveractive) { HTTPServer myServer = new HTTPServer(serverConnect.accept()); VerboseLogger.info("Connection opened. (" + Instant.now() + ")"); @@ -70,6 +72,7 @@ public class HTTPServer implements Runnable { // create dedicated thread to manage the client connection Thread thread = new Thread(myServer); thread.start(); + } } @@ -80,105 +83,108 @@ public class HTTPServer implements Runnable { @Override public void run() { - // we manage our particular client connection - BufferedReader in = null; PrintWriter out = null; BufferedOutputStream dataOut = null; - String fileRequested = null; + if (mcserveractive) { + // we manage our particular client connection + BufferedReader in = null; + PrintWriter out = null; + BufferedOutputStream dataOut = null; + String fileRequested = null; - try { - // we read characters from the client via input stream on the socket - in = new BufferedReader(new InputStreamReader(connect.getInputStream())); - // we get character output stream to client (for headers) - out = new PrintWriter(connect.getOutputStream()); - // get binary output stream to client (for requested data) - dataOut = new BufferedOutputStream(connect.getOutputStream()); + try { + // we read characters from the client via input stream on the socket + in = new BufferedReader(new InputStreamReader(connect.getInputStream())); + // we get character output stream to client (for headers) + out = new PrintWriter(connect.getOutputStream()); + // get binary output stream to client (for requested data) + dataOut = new BufferedOutputStream(connect.getOutputStream()); - // get first line of the request from the client - String input = in.readLine(); - // we parse the request with a string tokenizer - StringTokenizer parse = new StringTokenizer(input); - String method = parse.nextToken().toUpperCase(); // we get the HTTP method of the client - // we get file requested - fileRequested = parse.nextToken().toLowerCase(); + // get first line of the request from the client + String input = in.readLine(); + // we parse the request with a string tokenizer + StringTokenizer parse = new StringTokenizer(input); + String method = parse.nextToken().toUpperCase(); // we get the HTTP method of the client + // we get file requested + fileRequested = parse.nextToken().toLowerCase(); - // we support only GET and HEAD methods, we check - if (!method.equals("GET") && !method.equals("HEAD")) { - VerboseLogger.info("501 Not Implemented : " + method + " method."); + // we support only GET and HEAD methods, we check + if (!method.equals("GET") && !method.equals("HEAD")) { + VerboseLogger.info("501 Not Implemented : " + method + " method."); - // we return the not supported file to the client - Path file = WEB_ROOT.resolve(METHOD_NOT_SUPPORTED); - long fileLength = Files.size(file); - String contentMimeType = "text/html"; - //read content to return to client - byte[] fileData = readFileData(file); + // we return the not supported file to the client + Path file = WEB_ROOT.resolve(METHOD_NOT_SUPPORTED); + long fileLength = Files.size(file); + String contentMimeType = "text/html"; + //read content to return to client + byte[] fileData = readFileData(file); - // we send HTTP Headers with data to client - dataOut.write(NOT_IMPLEMENTED); - dataOut.write(HEADERS); //hopefully enough credits - dataOut.write("Date: %s\r\n".formatted(Instant.now()).getBytes(StandardCharsets.UTF_8)); - dataOut.write("Content-Type: %s\r\n".formatted(contentMimeType).getBytes(StandardCharsets.UTF_8)); - dataOut.write("Content-Length: %s\r\n".formatted(fileLength).getBytes(StandardCharsets.UTF_8)); - dataOut.write(CRLF); // blank line between headers and content, very important ! - // file - dataOut.write(fileData, 0, fileData.length); - dataOut.flush(); - - } else { - // GET or HEAD method - if (fileRequested.endsWith("/")) { - fileRequested += DEFAULT_FILE; - } - if (fileRequested.startsWith("/")) { - fileRequested = fileRequested.substring(1); - } - - Path file = WEB_ROOT.resolve(fileRequested).toRealPath(LinkOption.NOFOLLOW_LINKS); - if (!file.startsWith(WEB_ROOT)) { - VerboseLogger.warn("Access to file outside root: " + file); - throw new NoSuchFileException(fileRequested); - } - int fileLength = (int)Files.size(file); - String contentType = getContentType(fileRequested); - byte[] fileData = readFileData(file); - - // send HTTP Headers - dataOut.write(OK); - dataOut.write(HEADERS); - dataOut.write("Date: %s\r\n".formatted(Instant.now()).getBytes(StandardCharsets.UTF_8)); - dataOut.write("Content-Type: %s\r\n".formatted(contentType).getBytes(StandardCharsets.UTF_8)); - dataOut.write("Content-Length: %s\r\n".formatted(fileLength).getBytes(StandardCharsets.UTF_8)); - dataOut.write(CRLF); // blank line between headers and content, very important ! - if (method.equals("GET")) { // GET method so we return content - dataOut.write(fileData, 0, fileLength); + // we send HTTP Headers with data to client + dataOut.write(NOT_IMPLEMENTED); + dataOut.write(HEADERS); //hopefully enough credits + dataOut.write("Date: %s\r\n".formatted(Instant.now()).getBytes(StandardCharsets.UTF_8)); + dataOut.write("Content-Type: %s\r\n".formatted(contentMimeType).getBytes(StandardCharsets.UTF_8)); + dataOut.write("Content-Length: %s\r\n".formatted(fileLength).getBytes(StandardCharsets.UTF_8)); + dataOut.write(CRLF); // blank line between headers and content, very important ! + // file + dataOut.write(fileData, 0, fileData.length); dataOut.flush(); + + } else { + // GET or HEAD method + if (fileRequested.endsWith("/")) { + fileRequested += DEFAULT_FILE; + } + if (fileRequested.startsWith("/")) { + fileRequested = fileRequested.substring(1); + } + + Path file = WEB_ROOT.resolve(fileRequested).toRealPath(LinkOption.NOFOLLOW_LINKS); + if (!file.startsWith(WEB_ROOT)) { + VerboseLogger.warn("Access to file outside root: " + file); + throw new NoSuchFileException(fileRequested); + } + int fileLength = (int) Files.size(file); + String contentType = getContentType(fileRequested); + byte[] fileData = readFileData(file); + + // send HTTP Headers + dataOut.write(OK); + dataOut.write(HEADERS); + dataOut.write("Date: %s\r\n".formatted(Instant.now()).getBytes(StandardCharsets.UTF_8)); + dataOut.write("Content-Type: %s\r\n".formatted(contentType).getBytes(StandardCharsets.UTF_8)); + dataOut.write("Content-Length: %s\r\n".formatted(fileLength).getBytes(StandardCharsets.UTF_8)); + dataOut.write(CRLF); // blank line between headers and content, very important ! + if (method.equals("GET")) { // GET method so we return content + dataOut.write(fileData, 0, fileLength); + dataOut.flush(); + } + + VerboseLogger.info("File " + fileRequested + " of type " + contentType + " returned"); + } - VerboseLogger.info("File " + fileRequested + " of type " + contentType + " returned"); + } catch (NoSuchFileException e) { + try { + fileNotFound(out, dataOut, fileRequested); + } catch (IOException ioe) { + VerboseLogger.error("Error with file not found exception : " + ioe.getMessage()); + } - } - - } catch (NoSuchFileException e) { - try { - fileNotFound(out, dataOut, fileRequested); } catch (IOException ioe) { - VerboseLogger.error("Error with file not found exception : " + ioe.getMessage()); + VerboseLogger.error("Server error : " + ioe); + } finally { + try { + in.close(); + out.close(); + dataOut.close(); + connect.close(); // we close socket connection + } catch (Exception e) { + VerboseLogger.error("Error closing stream : " + e.getMessage()); + } + + VerboseLogger.info("Connection closed."); } - } catch (IOException ioe) { - VerboseLogger.error("Server error : " + ioe); - } finally { - try { - in.close(); - out.close(); - dataOut.close(); - connect.close(); // we close socket connection - } catch (Exception e) { - VerboseLogger.error("Error closing stream : " + e.getMessage()); - } - - VerboseLogger.info("Connection closed."); } - - } private byte[] readFileData(Path file) throws IOException { diff --git a/src/main/java/me/jonasjones/mcwebserver/web/ServerHandler.java b/src/main/java/me/jonasjones/mcwebserver/web/ServerHandler.java index 3d9cf22..4adae22 100644 --- a/src/main/java/me/jonasjones/mcwebserver/web/ServerHandler.java +++ b/src/main/java/me/jonasjones/mcwebserver/web/ServerHandler.java @@ -1,23 +1,23 @@ package me.jonasjones.mcwebserver.web; -import me.jonasjones.mcwebserver.McWebserver; -import net.minecraft.server.MinecraftServer; +import me.jonasjones.mcwebserver.config.ModConfigs; -public class ServerHandler extends Thread { - static ServerHandler thread = new ServerHandler(); - public static void startServer() { - McWebserver.LOGGER.info("Starting Webserver..."); - thread.start(); - } +import java.net.Socket; - public static void stopServer() throws InterruptedException { - McWebserver.LOGGER.info("Stopping Webserver..."); - thread.interrupt(); - McWebserver.LOGGER.info("Webserver stopped!"); - } +import static me.jonasjones.mcwebserver.McWebserver.LOGGER; + +public class ServerHandler implements Runnable { + public static Socket socket = new Socket(); public void run() { - HTTPServer.main(); + if (ModConfigs.IS_ENABLED) { + LOGGER.info("Starting Webserver..."); + + new HTTPServer(socket); + HTTPServer.main(); + } else { + LOGGER.info("Webserver disabled in the config file."); + } } } diff --git a/src/main/resources/mcwebserver.mixins.json b/src/main/resources/mcwebserver.mixins.json index aa57238..b6d7a65 100644 --- a/src/main/resources/mcwebserver.mixins.json +++ b/src/main/resources/mcwebserver.mixins.json @@ -1,9 +1,10 @@ { "required": true, "minVersion": "0.8", - "package": "net.fabricmc.example.mixin", + "package": "me.jonasjones.mcwebserver.mixin", "compatibilityLevel": "JAVA_17", "mixins": [ + "WebserverStopMixin" ], "injectors": { "defaultRequire": 1