java-refresher

Some quick exercises and small projects to help refresh my Java programming knowledge and skills.
git clone https://git.jaderune.net/jbauer/java-refresher
Log | Files | Refs | README | LICENSE

commit 8c9185f70eacc419ad85aba20515901cccdae43d
parent 7d35ee0a660d42c90007541c5a416a7914756854
Author: Jake Bauer <jbauer@paritybit.ca>
Date:   Sun, 21 May 2023 13:42:56 -0400

Write very simple webserver, capable of serving GET requests

Diffstat:
Awebserver/Main.java | 62++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Awebserver/index.html | 15+++++++++++++++
2 files changed, 77 insertions(+), 0 deletions(-)

diff --git a/webserver/Main.java b/webserver/Main.java @@ -0,0 +1,62 @@ +import java.net.*; +import java.io.*; +import java.nio.file.*; + +public class Main { + private static void handleRequest(Socket client) throws IOException { + BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream())); + StringBuilder requestReader = new StringBuilder(); + + String line; + while (!(line = in.readLine()).isBlank()) { + requestReader.append(line + "\r\n"); + } + + // Headers not considered + String[] request = requestReader.toString().split("\r\n"); + String method = request[0].split(" ")[0]; + String path = request[0].split(" ")[1]; + System.out.println(method + " " + path); + + // Serve the requested page or 404 + Path filePath = getFilePath(path); + if (Files.exists(filePath)) { + String contentType = Files.probeContentType(filePath); + sendResponse(client, "200 OK", contentType, Files.readAllBytes(filePath)); + } + else { + byte[] message = "<h1>404 File Not Found</h1>".getBytes(); + sendResponse(client, "404 Not Found", "text/html", message); + } + } + + private static void sendResponse(Socket client, String status, + String contentType, byte[] content) throws IOException { + OutputStream out = client.getOutputStream(); + out.write(("HTTP/1.1 " + status + "\r\n").getBytes()); + out.write(("ContentType: " + contentType + "\r\n").getBytes()); + out.write("\r\n".getBytes()); + out.write(content); + out.write("\r\n\r\n".getBytes()); + out.flush(); + client.close(); + } + + private static Path getFilePath(String path) { + if ("/".equals(path)) { + path = "/index.html"; + } + return Paths.get("./", path); + } + + public static void main(String[] args) throws Exception{ + // Listen using socket + try (ServerSocket server = new ServerSocket(8080)) { + while (true) { + try (Socket client = server.accept()) { + handleRequest(client); + } + } + } + } +} diff --git a/webserver/index.html b/webserver/index.html @@ -0,0 +1,15 @@ +<!DOCTYPE html> +<html lang=""> +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <link rel="icon" type="image/png" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAABX1BMVEUAAAABAAAAAAAAAAAAAAAAAAAAAAC7amoAAABlPz8AAAAAAAAGAwMAAAAAAAAAAAC7d3cKBwe7d3e7d3eWX1/ny4+WX18CAQGHVlaTXl4BAAApGhpiPj7ny4/ny4/oy4/ozI/qz5Ona2u7d3d4TEzny48MCAhlQEC7d3e7d3cAAAAAAAC7d3e8d3cAAAC8d3fnzI+8dnYAAADpzJC9eHjny4+WX1+TXV13S0u7d3fny492S0vnzI/ny4+EU1PnzI8mFxe7d3cjFhZgPT3ny5AAAAC7d3fny4+7d3cAAADozJC6d3e7d3cAAADozI/my5Dny44AAAAAAAC7d3e4d3fkx5DpzY69c3O7d3eoamroy4+FVVWEVFR0Skq7d3e7d3e8d3cAAAC6eHi7eHi7eHi8dna8dnYAAADozJAAAADkyY28eXnqyJHqzY63eHi/dXXny48AAAC7d3e5dXW2dHSjLYEdAAAAcHRSTlMA9cj58gYaBOrflhjq44MI/ePbaP348u/u6Oba1sW+oosL/Pbv7ejnyLuXlI54RkM8Oy4iG/v38efl4ODf2tfT09LQz87FwbeimJeJf397ZUlIRTQvGxYP9/Xv4ODZz86yk4JxYlRQSjctJiYlJCAYM3tXUgAAAg1JREFUOMttk1V3ImEQRO8MQ3CChACBIHF3l427+7q7Tjfz/88+sNhk67Vuf3K6CuryXo2Yfo/HbwYnvDxW25EldVnBNpfdHjVErO2dJ9nsk51tS8SItreMmyLxV46qakxVndW4iNl0yExEjHxFEyfTcz7f3PT7La0EDInM1PxQRMJZTSQbE5OvtbNLuv6d0W5K1zM99DXf6RvTnrCY1XdExcjqKcD9RbFQKF7cAyS105AoQJsheT0EyqWUbdu2badKZeBEA2KFgCOJVxI+uNu169q9A4YqAxIEryWr+hnKG3aTNsowrX2S9vJFLGcLOLZbdAwMO4ZMMCKbegq/5luB+VlIak6CmJLXGzi3XTqHOQ2IiV9e6gMU3EABeJoRPx7p7AXW3cA6kOgQTw1YcwNrNcAvL/QBut1AN9CbET+m5PUWSm6gBH90UEyCsqnjMOUGvsJHzckoV2I4Q8BBq38AvHUMucZryZJOwmx/s98/C7exPkl7YUTilTc+mHre5E8Bw5UBGa2uO6BjwPf6T7p/AuM6WF03UTEWNQlwWVxJpVaKlwCfYgseOatFLtyjYy2RYzzWE5Y9byO0izo02bBv9nUhXA9tNfaBiu5/+OED3+/ksFYGPRL55irOkqOqy8sxVadvQGQv9Kh6Ri6Q6ejIBHKGiHXmLnAomG6UNz0a+k+/vRPBav3fXTdN/wUXrszXABeiEwAAAABJRU5ErkJggg=="> + <title>Hello, World!</title> +<style>body{background-color:#fcfcfc;color:#111;line-height:1.4em;max-width:38em;margin:auto;padding-bottom:2em;font-family:"IBM Plex Serif", serif}header{text-align:center;margin:0.7em;font-size:2em;font-weight:bold}h1{font-style:oblique;margin-bottom:0;font-size:1.7em}h2,h3,h4,h5,h6{margin:1em 0 -0.2em;line-height:1.1em}nav{text-align:center}nav a{padding:0 0.5em;font-size:1.1em;font-weight:bold;text-decoration:none}nav a:hover{text-decoration:underline}a,nav a:visited{color:#134799}a:hover{text-decoration:none}a:visited{color:#551a8b}article a[href^="http"]:where(:not([href*="paritybit.ca/"]))::after{content:"︎↗"}figure a::after{content:""!important}img,video{max-width:100%}figcaption{text-align:center}blockquote{border-left:3px solid #134799;padding-left:0.5em}cite{margin-left:40px}summary:hover{cursor:pointer;background-color:#ddd}table{width:100%;text-align:left}table,td,th{border-collapse:collapse;border:1px solid #ddd;margin-top:1em;padding:2px 4px;vertical-align: top}th{background-color:#ddd}tr:nth-child(even){background-color:#eee}pre{background-color:#ddd;overflow:auto;padding:0.5em;border:1px black solid}code{background-color:#ddd;font-family:"IBM Plex Mono", monospace;font-size:0.9em}.note{border:3px solid #134799;margin:0.7em 0}.note p{margin:0.7em 0.9em}figcaption,.date{font-size:smaller;color:#565151}#icons{float:right}@media print{pre{white-space:pre-wrap}nav{display:none}}@media only screen and (max-width: 700px){body{max-width:90%}#icons{float:none}}</style> +</head> +<body> + <h1>Hello, World!</h1> + + <p>The server works!</p> +</body> +</html>