Archived
Private
Public Access
1
0

Initial commit

This commit is contained in:
2022-09-04 12:45:01 +02:00
commit f4a01d6a69
11601 changed files with 4206660 additions and 0 deletions

View File

@@ -0,0 +1,281 @@
package de.craftix;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
import de.craftix.api.RequestMethod;
import de.craftix.api.Route;
import de.craftix.api.SetMethod;
import de.craftix.api.WebApi;
import java.io.*;
import java.lang.reflect.Method;
import java.net.InetSocketAddress;
import java.nio.file.Files;
import java.util.HashMap;
import java.util.Map;
public class WebServer implements HttpHandler {
private static WebServer instance;
public static void start(int port, File contentRoot, boolean enableApiTester) {
instance = new WebServer(port, contentRoot, enableApiTester);
}
public static void addApi(WebApi api) {
if (!api.getClass().isAnnotationPresent(Route.class)) throw new IllegalStateException("API does not have a Route");
String route = api.getClass().getAnnotation(Route.class).value();
for (Method m : api.getClass().getMethods()) {
if (m.getParameters().length == 0) continue;
if (!m.getParameters()[0].getType().equals(HttpExchange.class)) continue;
String r = route + (m.isAnnotationPresent(Route.class) ? m.getAnnotation(Route.class).value() : "");
instance.apis.put(r, m);
instance.apiObjects.put(m, api);
}
}
private String contentRoot;
private boolean enableApiTester;
private File webRoot;
private final Map<String, Method> apis = new HashMap<>();
private final Map<Method, WebApi> apiObjects = new HashMap<>();
private WebServer(int port, File contentRoot, boolean enableApiTester) {
try {
HttpServer server = HttpServer.create(new InetSocketAddress(port), 0);
this.contentRoot = contentRoot.getAbsolutePath();
this.enableApiTester = enableApiTester;
//install typescript converter
System.out.println("Creating enviroment...");
this.webRoot = new File("webserver");
webRoot.delete();
webRoot.mkdirs();
ProcessBuilder builder = new ProcessBuilder();
builder.directory(webRoot);
builder.command("cmd.exe", "/c", "npm install typescript");
Process p = builder.start();
monitorProcess(p);
p.waitFor();
server.createContext("/", this);
server.start();
System.out.println("HttpServer started successfully on Port: " + server.getAddress().getPort());
}catch (Exception e) { e.printStackTrace(); }
}
@Override
public void handle(HttpExchange exchange) throws IOException {
String path = exchange.getRequestURI().getPath();
if (enableApiTester && path.equalsIgnoreCase("/apitester")) {
byte[] response = getApiTester();
exchange.sendResponseHeaders(200, response.length);
OutputStream out = exchange.getResponseBody();
out.write(response);
out.close();
}
if (apis.containsKey(path)) {
Method api = apis.get(path);
String method = api.isAnnotationPresent(SetMethod.class) ? api.getAnnotation(SetMethod.class).value().toString() : RequestMethod.GET.toString();
if (!exchange.getRequestMethod().equals(method)) {
byte[] response = enableApiTester ? getApiTester() : getFileContent("/index.html");
exchange.sendResponseHeaders(200, response.length);
OutputStream out = exchange.getResponseBody();
out.write(response);
out.close();
return;
}
try {
api.invoke(apiObjects.get(api), exchange);
} catch (Exception e) { e.printStackTrace(); }
} else {
byte[] response = getFileContent(path);
exchange.sendResponseHeaders(200, response.length);
OutputStream out = exchange.getResponseBody();
out.write(response);
out.close();
}
}
private byte[] getFileContent(String fileName) {
try {
if (fileName.endsWith("/")) return getFileContent(fileName + "index.html");
if (fileName.endsWith(".ts")) {
String out = webRoot.getAbsolutePath() + getFileName(fileName).replace(".ts", ".js");
String src = contentRoot + fileName;
ProcessBuilder builder = new ProcessBuilder();
builder.directory(webRoot);
builder.command("cmd.exe", "/c", "npx tsc", src, "--outFile", out);
Process p = builder.start();
monitorProcess(p);
p.waitFor();
System.out.println(out + 1);
return readFile(out);
}
return readFile(fileName);
}catch (Exception e) {
System.err.println("Client tried to access invalid path: " + fileName);
}
return enableApiTester ? getApiTester() : getFileContent("/index.html");
}
private byte[] readFile(String fileName) {
try {
return Files.readAllBytes(new File(contentRoot + fileName).toPath());
}catch (Exception e) {
System.err.println("Client tried to access invalid path: " + fileName);
}
return enableApiTester ? getApiTester() : getFileContent("/index.html");
}
private void monitorProcess(Process p) {
new Thread(() -> {
try {
BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
String str;
while ((str = br.readLine()) != null) {
System.out.println(str);
}
}catch (Exception ignored) {}
}).start();
new Thread(() -> {
try {
BufferedReader br = new BufferedReader(new InputStreamReader(p.getErrorStream()));
String str;
while ((str = br.readLine()) != null) {
System.out.println(str);
}
}catch (Exception ignored) {}
}).start();
}
private String getFileName(String path) {
path = path.replaceAll("//", "/");
String[] dirs = path.split("/");
return dirs[dirs.length - 1];
}
public static byte[] getBytesFromStream(InputStream in) {
try {
if (in == null) throw new NullPointerException("InputStream cannot be null");
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int nRead;
byte[] data = new byte[16384];
while ((nRead = in.read(data, 0, data.length)) != -1) {
buffer.write(data, 0, nRead);
}
return buffer.toByteArray();
}catch (Exception e) { e.printStackTrace(); }
return new byte[0];
}
public static byte[] getApiTester() {
return ("<!DOCTYPE html>\n" +
"<html lang=\"en\">\n" +
"<head>\n" +
" <meta charset=\"UTF-8\">\n" +
" <title>Http Request</title>\n" +
" <link href=\"https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css\" rel=\"stylesheet\" integrity=\"sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3\" crossorigin=\"anonymous\">\n" +
" <script src=\"https://cdn.jsdelivr.net/npm/@popperjs/core@2.10.2/dist/umd/popper.min.js\" integrity=\"sha384-7+zCNj/IqJ95wo16oMtfsKbZ9ccEh31eOz1HGyDuCQ6wgnyJNSYdrPa03rtR1zdB\" crossorigin=\"anonymous\"></script>\n" +
" <script src=\"https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.min.js\" integrity=\"sha384-QJHtvGhmr9XOIpI6YVutG+2QOK9T+ZnN4kzFN1RtK3zEFEIsxhlmWl5/YESvpZ13\" crossorigin=\"anonymous\"></script>\n" +
"\n" +
" <style>\n" +
" .hover:hover {\n" +
" cursor: pointer;\n" +
" }\n" +
"\n" +
" .unselectable {\n" +
" -webkit-touch-callout: none;\n" +
" -webkit-user-select: none;\n" +
" -moz-user-select: none;\n" +
" -ms-user-select: none;\n" +
" user-select: none;\n" +
" }\n" +
"\n" +
" #url_start {\n" +
" border-top-right-radius: 0;\n" +
" border-bottom-right-radius: 0;\n" +
" }\n" +
"\n" +
" #url {\n" +
" border-top-left-radius: 0;\n" +
" border-bottom-left-radius: 0;\n" +
" }\n" +
" </style>\n" +
"<body>\n" +
"\n" +
"<section style=\"margin-top: 20px\" id=\"options\">\n" +
" <p class=\"text-center unselectable\" style=\"font-size: 50px\">Send Http Request</p>\n" +
"\n" +
" <form class=\"container\">\n" +
" <div class=\"row\">\n" +
" <div class=\"col\">\n" +
" <label for=\"url\">URL</label>\n" +
" <div class=\"input-group mb-3\">\n" +
" <div class=\"input-group-prepend\">\n" +
" <span class=\"input-group-text\" id=\"url_start\"></span>\n" +
" </div>\n" +
" <input type=\"text\" class=\"form-control\" id=\"url\" aria-describedby=\"url_start\">\n" +
" </div>\n" +
" </div>\n" +
" <div class=\"dropdown col col-md-2\">\n" +
" <label for=\"method\" class=\"unselectable\">Select Method</label>\n" +
" <input class=\"btn btn-secondary dropdown-toggle form-control unselectable\" type=\"button\" id=\"method\" data-bs-toggle=\"dropdown\" aria-expanded=\"false\" value=\"GET\">\n" +
" <ul class=\"dropdown-menu\" aria-labelledby=\"method\">\n" +
" <li><a class=\"dropdown-item hover unselectable\" id=\"GET\">GET</a></li>\n" +
" <li><a class=\"dropdown-item hover unselectable\" id=\"POST\">POST</a></li>\n" +
" <li><a class=\"dropdown-item hover unselectable\" id=\"PUT\">PUT</a></li>\n" +
" <li><a class=\"dropdown-item hover unselectable\" id=\"DELETE\">DELETE</a></li>\n" +
" </ul>\n" +
" </div>\n" +
" </div>\n" +
" <br>\n" +
" <div class=\"mb-3\">\n" +
" <label class=\"form-check-label unselectable\" for=\"body\">Body</label>\n" +
" <textarea id=\"body\" class=\"form-control\" style=\"height: 200px\"></textarea>\n" +
" </div>\n" +
" <button type=\"button\" class=\"btn btn-primary unselectable\" id=\"send\">Send</button>\n" +
" </form>\n" +
"</section>\n" +
"\n" +
"<br><br>\n" +
"\n" +
"<section id=\"response\" class=\"container\"></section>\n" +
"\n" +
"<script>\n" +
" const url = new URL(window.location.href);\n" +
" const startUrl = url.protocol + \"//\" + url.hostname + \":\" + url.port + \"/\";\n" +
" document.getElementById(\"url_start\").innerHTML = startUrl;\n" +
"\n" +
" let method = \"GET\";\n" +
"\n" +
" const dropdowns = document.getElementsByClassName(\"dropdown-item\");\n" +
" for (let i = 0; i < dropdowns.length; i++) {\n" +
" const dropdown = dropdowns[i];\n" +
" dropdown.onclick = function () {\n" +
" method = dropdown.id;\n" +
" document.getElementById(\"method\").value = method;\n" +
" }\n" +
" }\n" +
"\n" +
" document.getElementById(\"send\").onclick = function () {\n" +
" const url = startUrl + document.getElementById(\"url\").value;\n" +
" const body = document.getElementById(\"body\").value;\n" +
" const Http = new XMLHttpRequest();\n" +
" Http.open(method, url, true);\n" +
" Http.onreadystatechange = function () {\n" +
" document.getElementById(\"response\").innerHTML = this.responseText;\n" +
" }\n" +
" Http.send(body);\n" +
" }\n" +
"</script>\n" +
"\n" +
"</body>\n" +
"</html>").getBytes();
}
}

View File

@@ -0,0 +1,20 @@
package de.craftix.api;
import com.sun.net.httpserver.HttpExchange;
import java.util.HashMap;
import java.util.Map;
public class HttpQuery {
private final Map<String, String> variables = new HashMap<>();
public HttpQuery(HttpExchange exchange) {
if (!exchange.getRequestURI().toString().contains("?")) return;
String raw = exchange.getRequestURI().getQuery();
String[] vars = raw.split("&");
for (String var : vars)
variables.put(var.split("=")[0].toLowerCase(), var.split("=")[1]);
}
public String getVariable(String name) { return variables.get(name.toLowerCase()) != null ? variables.get(name.toLowerCase()) : ""; }
}

View File

@@ -0,0 +1,17 @@
package de.craftix.api;
public enum RequestMethod {
GET("GET"),
POST("POST"),
PUT("PUT"),
DELETE("DELETE");
private final String type;
RequestMethod(String type) { this.type = type; }
public String getType() { return type; }
@Override
public String toString() { return type; }
}

View File

@@ -0,0 +1,12 @@
package de.craftix.api;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface Route {
String value();
}

View File

@@ -0,0 +1,12 @@
package de.craftix.api;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface SetMethod {
RequestMethod value() default RequestMethod.GET;
}

View File

@@ -0,0 +1,32 @@
package de.craftix.api;
import com.google.gson.Gson;
import com.sun.net.httpserver.HttpExchange;
import de.craftix.WebServer;
import java.io.OutputStream;
import java.io.Serializable;
import java.lang.reflect.Type;
public class WebApi {
protected void sendDataAsJson(HttpExchange exchange, Serializable data) {
if (data instanceof String) sendData(exchange, ((String) data).getBytes());
else sendData(exchange, new Gson().toJson(data).getBytes());
}
protected void sendData(HttpExchange exchange, byte[] data) {
try {
exchange.sendResponseHeaders(200, data.length);
OutputStream out = exchange.getResponseBody();
out.write(data);
out.close();
}catch (Exception e) { e.printStackTrace(); }
}
protected <T> T getDataFromBody(HttpExchange exchange, Type type) {
byte[] data = WebServer.getBytesFromStream(exchange.getRequestBody());
Gson gson = new Gson();
return gson.fromJson(new String(data), type);
}
}