some fixes I assume

This commit is contained in:
Jonas_Jones 2023-03-04 21:40:09 +01:00
parent 385879c305
commit 8d9deef4a6
7 changed files with 149 additions and 118 deletions

View file

@ -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. // 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}" // modImplementation "net.fabricmc.fabric-api:fabric-api-deprecated:${project.fabric_version}"
implementation files('libs/java-curl-1.2.2.jar')
} }
processResources { processResources {

BIN
libs/java-curl-1.2.2.jar Normal file

Binary file not shown.

View file

@ -1,12 +1,15 @@
package me.jonasjones.mcwebserver; package me.jonasjones.mcwebserver;
import com.roxstudio.utils.CUrl;
import me.jonasjones.mcwebserver.config.ModConfigs; import me.jonasjones.mcwebserver.config.ModConfigs;
import me.jonasjones.mcwebserver.web.HTTPServer; import me.jonasjones.mcwebserver.web.ServerHandler;
import net.fabricmc.api.ModInitializer; import net.fabricmc.api.ModInitializer;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; 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 { public class McWebserver implements ModInitializer {
// This logger is used to write text to the console and the log file. // 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 String MOD_ID = "mcwebserver";
public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID); public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID);
public static final Logger VERBOSELOGGER = LoggerFactory.getLogger(MOD_ID + " - VERBOSE LOGGER"); 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 @Override
public void onInitialize() { public void onInitialize() {
@ -24,15 +30,30 @@ public class McWebserver implements ModInitializer {
LOGGER.info("McWebserver initialized!"); LOGGER.info("McWebserver initialized!");
if (ModConfigs.IS_ENABLED) {
LOGGER.info("Starting Webserver...");
new Thread(() -> { webserverthread.start();
new HTTPServer(new Socket()); new Thread(() -> {
HTTPServer.main(); while (true) {
}).start(); if (!mcserveractive) {
} else { LOGGER.info("LMFAFMAKONJDGOADJINGOADNGHOADNHGOADNHOADHON");
LOGGER.info("Webserver disabled in the config file."); 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();
} }
} }

View file

@ -1,16 +1,17 @@
package me.jonasjones.mcwebserver.mixin; package me.jonasjones.mcwebserver.mixin;
import me.jonasjones.mcwebserver.McWebserver; 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.Mixin;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(TitleScreen.class) @Mixin(MinecraftServer.class)
public class InitializeMixin { public class WebserverStopMixin {
@Inject(at = @At("HEAD"), method = "init()V") @Inject(at = @At("HEAD"), method = "shutdown")
private void init(CallbackInfo info) { 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;
} }
} }

View file

@ -20,6 +20,8 @@ import java.nio.file.Path;
import java.time.Instant; import java.time.Instant;
import java.util.StringTokenizer; import java.util.StringTokenizer;
import static me.jonasjones.mcwebserver.McWebserver.mcserveractive;
public class HTTPServer implements Runnable { public class HTTPServer implements Runnable {
static Path WEB_ROOT; static Path WEB_ROOT;
static final String DEFAULT_FILE = ModConfigs.WEB_FILE_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); McWebserver.LOGGER.info("Listening for connections on port : " + PORT);
// we listen until user halts server execution // we listen until user halts server execution
while (true) { while (mcserveractive) {
HTTPServer myServer = new HTTPServer(serverConnect.accept()); HTTPServer myServer = new HTTPServer(serverConnect.accept());
VerboseLogger.info("Connection opened. (" + Instant.now() + ")"); VerboseLogger.info("Connection opened. (" + Instant.now() + ")");
@ -70,6 +72,7 @@ public class HTTPServer implements Runnable {
// create dedicated thread to manage the client connection // create dedicated thread to manage the client connection
Thread thread = new Thread(myServer); Thread thread = new Thread(myServer);
thread.start(); thread.start();
} }
} }
@ -80,105 +83,108 @@ public class HTTPServer implements Runnable {
@Override @Override
public void run() { public void run() {
// we manage our particular client connection if (mcserveractive) {
BufferedReader in = null; PrintWriter out = null; BufferedOutputStream dataOut = null; // we manage our particular client connection
String fileRequested = null; BufferedReader in = null;
PrintWriter out = null;
BufferedOutputStream dataOut = null;
String fileRequested = null;
try { try {
// we read characters from the client via input stream on the socket // we read characters from the client via input stream on the socket
in = new BufferedReader(new InputStreamReader(connect.getInputStream())); in = new BufferedReader(new InputStreamReader(connect.getInputStream()));
// we get character output stream to client (for headers) // we get character output stream to client (for headers)
out = new PrintWriter(connect.getOutputStream()); out = new PrintWriter(connect.getOutputStream());
// get binary output stream to client (for requested data) // get binary output stream to client (for requested data)
dataOut = new BufferedOutputStream(connect.getOutputStream()); dataOut = new BufferedOutputStream(connect.getOutputStream());
// get first line of the request from the client // get first line of the request from the client
String input = in.readLine(); String input = in.readLine();
// we parse the request with a string tokenizer // we parse the request with a string tokenizer
StringTokenizer parse = new StringTokenizer(input); StringTokenizer parse = new StringTokenizer(input);
String method = parse.nextToken().toUpperCase(); // we get the HTTP method of the client String method = parse.nextToken().toUpperCase(); // we get the HTTP method of the client
// we get file requested // we get file requested
fileRequested = parse.nextToken().toLowerCase(); fileRequested = parse.nextToken().toLowerCase();
// we support only GET and HEAD methods, we check // we support only GET and HEAD methods, we check
if (!method.equals("GET") && !method.equals("HEAD")) { if (!method.equals("GET") && !method.equals("HEAD")) {
VerboseLogger.info("501 Not Implemented : " + method + " method."); VerboseLogger.info("501 Not Implemented : " + method + " method.");
// we return the not supported file to the client // we return the not supported file to the client
Path file = WEB_ROOT.resolve(METHOD_NOT_SUPPORTED); Path file = WEB_ROOT.resolve(METHOD_NOT_SUPPORTED);
long fileLength = Files.size(file); long fileLength = Files.size(file);
String contentMimeType = "text/html"; String contentMimeType = "text/html";
//read content to return to client //read content to return to client
byte[] fileData = readFileData(file); byte[] fileData = readFileData(file);
// we send HTTP Headers with data to client // we send HTTP Headers with data to client
dataOut.write(NOT_IMPLEMENTED); dataOut.write(NOT_IMPLEMENTED);
dataOut.write(HEADERS); //hopefully enough credits dataOut.write(HEADERS); //hopefully enough credits
dataOut.write("Date: %s\r\n".formatted(Instant.now()).getBytes(StandardCharsets.UTF_8)); 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-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("Content-Length: %s\r\n".formatted(fileLength).getBytes(StandardCharsets.UTF_8));
dataOut.write(CRLF); // blank line between headers and content, very important ! dataOut.write(CRLF); // blank line between headers and content, very important !
// file // file
dataOut.write(fileData, 0, fileData.length); 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(); 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) { } 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 { private byte[] readFileData(Path file) throws IOException {

View file

@ -1,23 +1,23 @@
package me.jonasjones.mcwebserver.web; package me.jonasjones.mcwebserver.web;
import me.jonasjones.mcwebserver.McWebserver; import me.jonasjones.mcwebserver.config.ModConfigs;
import net.minecraft.server.MinecraftServer;
public class ServerHandler extends Thread { import java.net.Socket;
static ServerHandler thread = new ServerHandler();
public static void startServer() {
McWebserver.LOGGER.info("Starting Webserver...");
thread.start();
}
public static void stopServer() throws InterruptedException { import static me.jonasjones.mcwebserver.McWebserver.LOGGER;
McWebserver.LOGGER.info("Stopping Webserver...");
thread.interrupt(); public class ServerHandler implements Runnable {
McWebserver.LOGGER.info("Webserver stopped!"); public static Socket socket = new Socket();
}
public void run() { 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.");
}
} }
} }

View file

@ -1,9 +1,10 @@
{ {
"required": true, "required": true,
"minVersion": "0.8", "minVersion": "0.8",
"package": "net.fabricmc.example.mixin", "package": "me.jonasjones.mcwebserver.mixin",
"compatibilityLevel": "JAVA_17", "compatibilityLevel": "JAVA_17",
"mixins": [ "mixins": [
"WebserverStopMixin"
], ],
"injectors": { "injectors": {
"defaultRequire": 1 "defaultRequire": 1