/* neon - Embeddable HTTP Server based on jdk.httpserver Copyright (C) 2024 Ulrich Hilger This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . */ package de.uhilger.neon; import com.sun.net.httpserver.Headers; import com.sun.net.httpserver.HttpExchange; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.nio.file.Files; import java.text.SimpleDateFormat; import java.util.Date; /** * Helfer zur Beantwortung von HTTP-Anfragen * * @author Ulrich Hilger * @version 1, 03.06.2021 */ public class HttpResponder { /* Headernamen */ public static final String ACCEPT_RANGES_HEADER = "Accept-Ranges"; public static final String CONTENT_LENGTH = "Content-Length"; public static final String CONTENT_TYPE = "Content-Type"; public static final String LAST_MODIFIED_DATE_HEADER = "Last-Modified"; /* Statuscodes */ public static final int SC_OK = 200; public static final int SC_NOT_FOUND = 404; public static final int SC_METHOD_NOT_ALLOWED = 405; public static final int SC_UNPROCESSABLE_ENTITY = 422; public static final int SC_INTERNAL_SERVER_ERROR = 500; /* String Konstanten */ public static final String STR_BYTES = "bytes"; public static final String STR_NOT_FOUND = " not found."; public static final String LM_PATTERN = "EEE, dd MMM yyyy HH:mm:ss zzz"; /** * Den Inhalt einer Datei ausliefern * * @param e das Objekt mit Methoden zur Untersuchung der Anfrage sowie zum * Anfertigen und Senden der Antwort * @param file die Datei, deren Inhalt ausgeliefert werden soll * @throws IOException falls etwas schief geht entsteht dieser Fehler */ public void serveFile(HttpExchange e, File file) throws IOException { if (file.exists()) { setHeaders(e, file); e.getResponseHeaders().set(CONTENT_LENGTH, Long.toString(file.length())); e.sendResponseHeaders(SC_OK, file.length()); if(HttpHelper.HTTP_GET.equalsIgnoreCase(e.getRequestMethod())) { InputStream in = new FileInputStream(file); OutputStream os = e.getResponseBody(); write(in, os); finish(in, os); } } else { sendNotFound(e, file.getName()); } } public void write(InputStream in, OutputStream out) throws IOException { byte[] b = new byte[4096]; int bytesRead = in.read(b); while (bytesRead > -1) { out.write(b, 0, bytesRead); bytesRead = in.read(b); } } public void finish(InputStream in, OutputStream out) throws IOException { in.close(); finish(out); } public void finish(OutputStream out) throws IOException { out.flush(); out.close(); } /** * Die Header erzeugen, die unabhängig davon, ob der ganze * Inhalt oder nur Teile davon ausgeliefert werden sollen, in der * Antwort stehen sollen * * @param e das Objekt mit Methoden zur Untersuchung der Anfrage sowie zum * Anfertigen und Senden der Antwort * @param file die Datei, für die die Header gelten * @throws IOException falls etwas schief geht entsteht dieser Fehler */ public void setHeaders(HttpExchange e, File file) throws IOException { Headers resHeaders = e.getResponseHeaders(); resHeaders.add(ACCEPT_RANGES_HEADER, STR_BYTES); String mimeType = Files.probeContentType(file.toPath()); if (mimeType != null) { resHeaders.add(CONTENT_TYPE, mimeType); } SimpleDateFormat sdf = new SimpleDateFormat(LM_PATTERN); Date date = new Date(file.lastModified()); resHeaders.add(LAST_MODIFIED_DATE_HEADER, sdf.format(date)); } /** * Eine nicht gefunden Antwort senden * * @param e das Objekt mit Methoden zur Untersuchung der Anfrage sowie zum * Anfertigen und Senden der Antwort * @param fname Name der Datei, die nicht gefunden wurde * @throws IOException falls etwas schief geht entsteht dieser Fehler */ public void sendNotFound(HttpExchange e, String fname) throws IOException { antwortSenden(e, SC_NOT_FOUND, fname + STR_NOT_FOUND); } public void antwortSenden(HttpExchange exchange, int code, String antwort) throws IOException { byte[] bytes = antwort.getBytes(); exchange.sendResponseHeaders(code, bytes.length); OutputStream os = exchange.getResponseBody(); os.write(bytes); finish(os); } }