diff --git a/src/main/java/de/igslandstuhl/database/server/WebServer.java b/src/main/java/de/igslandstuhl/database/server/WebServer.java index 0dec0ae..d7dd636 100644 --- a/src/main/java/de/igslandstuhl/database/server/WebServer.java +++ b/src/main/java/de/igslandstuhl/database/server/WebServer.java @@ -72,7 +72,7 @@ class ClientHandler implements Runnable { @Override public void run() { try (BufferedOutputStream rawOut = new BufferedOutputStream(clientSocket.getOutputStream())) { - PrintWriter out = new PrintWriter(new OutputStreamWriter(rawOut, StandardCharsets.UTF_8), true); + PrintStream out = new PrintStream(rawOut, true, StandardCharsets.UTF_8); try (BufferedInputStream bis = new BufferedInputStream(clientSocket.getInputStream())) { String headerString = readHeadersAsString(bis); if (headerString == null) { @@ -90,7 +90,7 @@ public void run() { } catch (Exception e) { e.printStackTrace(); try { - PrintWriter out = new PrintWriter(new OutputStreamWriter(clientSocket.getOutputStream(), StandardCharsets.UTF_8), true); + PrintStream out = new PrintStream(clientSocket.getOutputStream(), true); GetResponse.internalServerError().respond(out); } catch (IOException ignored) {} } finally { @@ -104,14 +104,14 @@ String readHeadersAsString(InputStream in) throws IOException { return new String(headerBytes, StandardCharsets.ISO_8859_1); } - void handleGet(String headerString, PrintWriter out) { + void handleGet(String headerString, PrintStream out) { String user = Server.getInstance().getWebServer().getUserManager().getSessionUser(headerString); GetRequest get = new GetRequest(headerString); GetResponse response = GetResponse.getResource(get.toResourceLocation(user), user); response.respond(out); } - void handlePost(String headerString, InputStream in, PrintWriter out) throws IOException { + void handlePost(String headerString, InputStream in, PrintStream out) throws IOException { Map headerMap = parseHeaders(headerString); PostHeader postHeader = new PostHeader(headerString); int contentLength = headerMap.containsKey("content-length") ? Integer.parseInt(headerMap.get("content-length")) : 0; diff --git a/src/main/java/de/igslandstuhl/database/server/webserver/ContentType.java b/src/main/java/de/igslandstuhl/database/server/webserver/ContentType.java index 56600c7..862e228 100644 --- a/src/main/java/de/igslandstuhl/database/server/webserver/ContentType.java +++ b/src/main/java/de/igslandstuhl/database/server/webserver/ContentType.java @@ -31,6 +31,18 @@ private ContentType(String name) { public String getName() { return name; } + public boolean isText() { + switch (this) { + case TEXT_PLAIN: + case HTML: + case JAVASCRIPT: + case CSS: + case JSON: + return true; + default: + return false; + } + } /** * Returns the ContentType corresponding to the given ResourceLocation. * @param l the ResourceLocation to determine the content type for diff --git a/src/main/java/de/igslandstuhl/database/server/webserver/GetResponse.java b/src/main/java/de/igslandstuhl/database/server/webserver/GetResponse.java index 4b947ac..0513042 100644 --- a/src/main/java/de/igslandstuhl/database/server/webserver/GetResponse.java +++ b/src/main/java/de/igslandstuhl/database/server/webserver/GetResponse.java @@ -1,7 +1,8 @@ package de.igslandstuhl.database.server.webserver; import java.io.FileNotFoundException; -import java.io.PrintWriter; +import java.io.InputStream; +import java.io.PrintStream; import de.igslandstuhl.database.server.resources.ResourceHelper; import de.igslandstuhl.database.server.resources.ResourceLocation; @@ -116,24 +117,33 @@ public static GetResponse getResource(ResourceLocation resourceLocation, String * This method formats the HTTP response header and body, including the status, content type, and resource. * @param out the PrintWriter to write the response to */ - public void respond(PrintWriter out) { + public void respond(PrintStream out) { try { - String resource = ""; - if (resourceLocation != null) { - if (!resourceLocation.isVirtual()) { - resource = ResourceHelper.readResourceCompletely(resourceLocation); - } else { - resource = ResourceHelper.readVirtualResource(user, resourceLocation); - if (resource == null) throw new NullPointerException(); - } - } out.print("HTTP/1.1 "); status.write(out); out.println(); if (contentType != null) { out.print("Content-Type: "); out.print(contentType.getName()); - out.print("; charset="); out.println(charset); + if (contentType.isText()) { + out.print("; charset=");out.print(charset); + } + out.println(); + } + out.println(); // <--- This line is important: seperates Header and Body! + if (contentType.isText()) { + String resource = ""; + if (resourceLocation != null) { + if (!resourceLocation.isVirtual()) { + resource = ResourceHelper.readResourceCompletely(resourceLocation); + } else { + resource = ResourceHelper.readVirtualResource(user, resourceLocation); + if (resource == null) throw new NullPointerException(); + } + } + out.println(resource); + } else { + try (InputStream in = ResourceHelper.openResourceAsStream(resourceLocation)) { + in.transferTo(out); // Streams bytes directly + } } - out.println(); // <--- Diese Zeile ist wichtig: trennt Header von Body! - out.println(resource); } catch (FileNotFoundException e) { notFound().respond(out); } catch (Exception e) { diff --git a/src/main/java/de/igslandstuhl/database/server/webserver/PostResponse.java b/src/main/java/de/igslandstuhl/database/server/webserver/PostResponse.java index 172b434..2ce21d0 100644 --- a/src/main/java/de/igslandstuhl/database/server/webserver/PostResponse.java +++ b/src/main/java/de/igslandstuhl/database/server/webserver/PostResponse.java @@ -1,7 +1,7 @@ package de.igslandstuhl.database.server.webserver; import java.io.FileNotFoundException; -import java.io.PrintWriter; +import java.io.PrintStream; import de.igslandstuhl.database.server.resources.ResourceLocation; @@ -92,7 +92,7 @@ private PostResponse(Status statusCode, String body, ContentType contentType, St * * @param out The PrintWriter to write the response to. */ - public void respond(PrintWriter out) { + public void respond(PrintStream out) { out.print("HTTP/1.1 "); statusCode.write(out); out.print("\r\n"); diff --git a/src/main/java/de/igslandstuhl/database/server/webserver/Status.java b/src/main/java/de/igslandstuhl/database/server/webserver/Status.java index 3f472a7..283aa9b 100644 --- a/src/main/java/de/igslandstuhl/database/server/webserver/Status.java +++ b/src/main/java/de/igslandstuhl/database/server/webserver/Status.java @@ -1,5 +1,6 @@ package de.igslandstuhl.database.server.webserver; +import java.io.PrintStream; import java.io.PrintWriter; /** @@ -58,4 +59,12 @@ public String getMessage() { public void write(PrintWriter out) { out.print(code);out.print(" ");out.print(name); } + /** + * Writes the HTTP status code and name to the given PrintStream. + * This is used to format the HTTP response header. + * @param out the PrintWriter to write to + */ + public void write(PrintStream out) { + out.print(code);out.print(" ");out.print(name); + } } \ No newline at end of file diff --git a/src/test/java/de/igslandstuhl/database/server/webserver/GetResponseTest.java b/src/test/java/de/igslandstuhl/database/server/webserver/GetResponseTest.java index 8b399f3..0fcf6a8 100644 --- a/src/test/java/de/igslandstuhl/database/server/webserver/GetResponseTest.java +++ b/src/test/java/de/igslandstuhl/database/server/webserver/GetResponseTest.java @@ -2,9 +2,9 @@ import static org.junit.jupiter.api.Assertions.*; +import java.io.ByteArrayOutputStream; import java.io.FileNotFoundException; -import java.io.PrintWriter; -import java.io.StringWriter; +import java.io.PrintStream; import org.junit.jupiter.api.Test; @@ -43,11 +43,11 @@ void testGetResponseBody() { @Test void testRespond() throws FileNotFoundException { - StringWriter testWriter = new StringWriter(); - PrintWriter printWriter = new PrintWriter(testWriter); + ByteArrayOutputStream testStream = new ByteArrayOutputStream(); + PrintStream printWriter = new PrintStream(testStream); GetResponse response = GetResponse.getResource(ResourceLocation.get("html", "site:login.html"), null); response.respond(printWriter); - String responseString = testWriter.toString(); + String responseString = testStream.toString(); String responseBody = response.getResponseBody(); assertTrue(responseString.contains(responseBody)); assertTrue(responseString.contains("HTTP/1.1 200 OK")); diff --git a/src/test/java/de/igslandstuhl/database/server/webserver/PostResponseTest.java b/src/test/java/de/igslandstuhl/database/server/webserver/PostResponseTest.java index 4cccbfa..ca6d957 100644 --- a/src/test/java/de/igslandstuhl/database/server/webserver/PostResponseTest.java +++ b/src/test/java/de/igslandstuhl/database/server/webserver/PostResponseTest.java @@ -1,15 +1,15 @@ package de.igslandstuhl.database.server.webserver; -import java.io.PrintWriter; -import java.io.StringWriter; +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; import org.junit.jupiter.api.Test; public class PostResponseTest { private String read(PostResponse r) { - StringWriter w = new StringWriter(); - r.respond(new PrintWriter(w)); - return w.toString(); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + r.respond(new PrintStream(out)); + return out.toString(); } @Test void testBadRequest() {