Skip to content
Snippets Groups Projects
Main.java 8.9 KiB
Newer Older
//TIP To <b>Run</b> code, press <shortcut actionId="Run"/> or
// click the <icon src="AllIcons.Actions.Execute"/> icon in the gutter.

import java.awt.*;
import java.io.*;
import java.net.InetSocketAddress;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;

import javax.swing.*;

public class Main {

    private static final String NAME = "TinyHost";
    private static final String VERSION = "0.5";
    private static final String HOME = "https://gitlab.informatik.uni-bremen.de/phaker/tinyhost";

    private static final Map<String,String> MIME_MAP = new HashMap<>();
    private static final String DEFAULT_MIME_TYPE = "text/plain";
    static {
        MIME_MAP.put("appcache", "text/cache-manifest");
        MIME_MAP.put("css", "text/css");
        MIME_MAP.put("gif", "image/gif");
        MIME_MAP.put("html", "text/html");
        MIME_MAP.put("js", "application/javascript");
        MIME_MAP.put("json", "application/json");
        MIME_MAP.put("jpg", "image/jpeg");
        MIME_MAP.put("jpeg", "image/jpeg");
        MIME_MAP.put("mp4", "video/mp4");
        MIME_MAP.put("pdf", "application/pdf");
        MIME_MAP.put("png", "image/png");
        MIME_MAP.put("svg", "image/svg+xml");
        MIME_MAP.put("xlsm", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        MIME_MAP.put("xml", "application/xml");
        MIME_MAP.put("zip", "application/zip");
        MIME_MAP.put("md", "text/plain");
        MIME_MAP.put("txt", "text/plain");
        MIME_MAP.put("php", "text/plain");
        MIME_MAP.put("wasm", "application/wasm");
    }

    public static void main(String[] args) {
        System.out.printf("Welcome to %s v%s%n", NAME, VERSION);

        if (args.length >= 2) {
            final String param = args[1];
            final Path targetPath = new File(param).toPath();
            UI ui = UI.defaultImpl();
            switch (args[0].toLowerCase()) {
                case "unhost" -> {
                    ReHost.unhost(targetPath, ui);
                    return;
                }
                case "host" -> {
                    Either<String, ArrayIndexOutOfBoundsException> content = Either.of(() -> args[2]);
                    switch (content) {
                        case Either.Left<String, ArrayIndexOutOfBoundsException> left ->
                            ReHost.host(new File(left.left()).toPath(), targetPath, ui);

                        case Either.Right<String, ArrayIndexOutOfBoundsException> right ->
                            right.right().printStackTrace(System.out);

                    }
                    return;
                }
                case "add" -> {
                    Either<String, ArrayIndexOutOfBoundsException> content = Either.of(() -> args[2]);
                    switch (content) {
                        case Either.Left<String, ArrayIndexOutOfBoundsException> left ->
                                ReHost.addHostedContent(new File(left.left()).toPath(), targetPath, ui);

                        case Either.Right<String, ArrayIndexOutOfBoundsException> right ->
                                right.right().printStackTrace(System.out);

                    }
                    return;
                }
            }
        }


        HttpServer server = null;
        int port = -1;
        do {
            String portString = JOptionPane.showInputDialog("Bitte den Port angeben:", "8080");
            try {
                port = Integer.parseInt(portString);
                if (port <= 0) {
                    throw new IllegalArgumentException();
                }
                server = HttpServer.create(new InetSocketAddress(port), 0);
            } catch (Exception ignored) {}
        } while (server == null);

        int finalPort = port;
        Thread openBrowser = new Thread(() -> {
            try {
                Thread.sleep(1000);
            } catch (Exception ignored) {}
            openURL(String.format("http://localhost:%d/", finalPort));
        });
        openBrowser.start();


        Thread quitServer = new Thread(()-> {
            Object[] options = {"Beenden"};
            int ignored = JOptionPane.showOptionDialog(null,
                    "Soll der Server beendet werden?",
                    "",
                    JOptionPane.DEFAULT_OPTION,
                    JOptionPane.QUESTION_MESSAGE,
                    null,     //do not use a custom Icon
                    options,  //the titles of buttons
                    options[0]); //default button title
            System.exit(0);
        });

        quitServer.start();

        server.createContext("/", new MyHandler());
        server.setExecutor(null); // creates a default executor


        server.start();


    }

    static class MyHandler implements HttpHandler {
        @Override
        public void handle(HttpExchange t) throws IOException {
            System.out.println("Requested: " + t.getRequestURI());


            int code;
            byte[] response;
            String mimeType;

            if (t.getRequestMethod().equals("GET")) {
                String uriString = t.getRequestURI().toString();
                if (uriString.equals("/")) {
                    uriString = "/index.html";
                }

                uriString = "/content" + uriString;

                if (uriString.endsWith(".class") || uriString.endsWith("MANIFEST.MF")) {
                    code = 404;
                    response = "Please don't request the Servers Code-Files. The Server does not like that :(".getBytes();
                    mimeType = DEFAULT_MIME_TYPE;
                } else {
                    try (InputStream in = getClass().getResourceAsStream(uriString)) {
                        code = 200;

                        assert in != null;
                        response = in.readAllBytes();

                        mimeType = getMimeType(uriString);
                        System.out.println("Delivered: " + uriString);
                    } catch (Exception e) {
                        code = 404;
                        mimeType = "text/html";
                        response = createErrorResponse(t, uriString, e).getBytes();
                    }
                }
            } else {
                code = 405;
                response = "Please only use GET".getBytes();
                mimeType = DEFAULT_MIME_TYPE;
            }

            t.getResponseHeaders().set("Content-Type", mimeType);
            t.sendResponseHeaders(code, response.length);


            OutputStream os = t.getResponseBody();
            os.write(response);

            os.close();
        }
    }

    private static String createErrorResponse(HttpExchange t, String uriString, Exception e) {
        StringBuilder builder = new StringBuilder();
        for (StackTraceElement line : e.getStackTrace()) {
            builder.append("<li>").append(line).append("</li>");
        }
        return String.format(
        """
        <!DOCTYPE html>
        <html>
            <head>
                <title>%s - 404</title>
                <style>
        body {
          background-color: #252D28;
          color: #ADADAD;
        }
        sub {
          color: #FFA200;
        }
        code {
          background-color: #1A1F1C;
        }
                </style>
            </head>
            <body>
                Thank you for using <a target="_blank" href="%s"><sub>%s</sub></a><br/>
                <span>The server ran into a problem serving requested resource <code>%s</code> which should have been at <code>%s</code>.</span>
                <ol>%s</ol>
            </body>
        </html>
        """, NAME, HOME, NAME, t.getRequestURI(), uriString, builder);

    }

    public static void openURL(String url) {
        if(Desktop.isDesktopSupported()){
            Desktop desktop = Desktop.getDesktop();
            try {
                desktop.browse(new URI(url));
            } catch (IOException | URISyntaxException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }else{
            Runtime runtime = Runtime.getRuntime();
            try {
                runtime.exec(new String[]{"xdg-open", url});
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

    public static String getMimeType(String uri) {
        Optional<String> extension = Optional.ofNullable(uri)
                .filter(f -> f.contains("."))
                .map(f -> f.substring(uri.lastIndexOf(".") + 1));

        String type = extension.flatMap(ext -> Optional.ofNullable(MIME_MAP.get(ext))).orElse(DEFAULT_MIME_TYPE);

        System.out.println("Type for >" + uri + "< is >" + type + "<");

        return type;
    }
}