From 8abbcfbb478405ca5f61218018ac5d61104d6f35 Mon Sep 17 00:00:00 2001
From: ulrich
Date: Fri, 26 Mar 2021 14:50:39 +0000
Subject: [PATCH] FileHandler erweitert (not found)
---
src/de/uhilger/minsrv/App.java | 2
src/de/uhilger/minsrv/handler/FileHandler.java | 277 ++++++++++++++++++++++++++++++-------------------------
src/de/uhilger/minsrv/handler/StopServerHandler.java | 2
src/de/uhilger/minsrv/Server.java | 2
4 files changed, 155 insertions(+), 128 deletions(-)
diff --git a/src/de/uhilger/minsrv/App.java b/src/de/uhilger/minsrv/App.java
index f52880e..59785ea 100644
--- a/src/de/uhilger/minsrv/App.java
+++ b/src/de/uhilger/minsrv/App.java
@@ -26,7 +26,7 @@
/**
* Die Hauptklasse des mini-server
*
- * @author ulrich
+ * @author Ulrich Hilger
* @version 0.1, 25.03.2021
*/
public class App {
diff --git a/src/de/uhilger/minsrv/Server.java b/src/de/uhilger/minsrv/Server.java
index 1f51964..6935d9a 100644
--- a/src/de/uhilger/minsrv/Server.java
+++ b/src/de/uhilger/minsrv/Server.java
@@ -30,7 +30,7 @@
* Die Klasse Server stellt Methoden zur Ausführung eines
* HTTP-Servers bereit
*
- * @author ulrich
+ * @author Ulrich Hilger
* @version 0.1, 25.03.2021
*/
public class Server {
diff --git a/src/de/uhilger/minsrv/handler/FileHandler.java b/src/de/uhilger/minsrv/handler/FileHandler.java
index d9d12b4..033fa58 100644
--- a/src/de/uhilger/minsrv/handler/FileHandler.java
+++ b/src/de/uhilger/minsrv/handler/FileHandler.java
@@ -14,7 +14,7 @@
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
-*/
+ */
package de.uhilger.minsrv.handler;
import com.sun.net.httpserver.Headers;
@@ -34,82 +34,93 @@
import java.util.logging.Logger;
/**
- * Die Klasse FileHandler dient zur Auslieferung von Dateiinhalten
- * über HTTP.
- *
- * @author ulrich
+ * Die Klasse FileHandler dient zur Auslieferung von Dateiinhalten über
+ * HTTP.
+ *
+ * @author Ulrich Hilger
* @version 0.1, 25. März 2021
*/
public class FileHandler implements HttpHandler {
-
+
+ /* Der Logger fuer diesen FileHandler */
private static final Logger logger = Logger.getLogger(FileHandler.class.getName());
+ /* Header Namen */
final static String RANGE_HEADER = "Range";
final static String CONTENT_RANGE_HEADER = "Content-Range";
final static String ACCEPT_RANGES_HEADER = "Accept-Ranges";
final static String LAST_MODIFIED_DATE_HEADER = "Last-Modified";
final static String CONTENT_TYPE = "Content-Type";
-
+
+ /* Status Codes */
+ public static final int SC_OK = 200;
public static final int SC_PARTIAL_CONTENT = 206;
-
+ public static final int SC_NOT_FOUND = 404;
+
+ /* Ablageort fuer Webinhalte */
private final String basePath;
/**
* Ein neues Objekt der Klasse FileHandler erzeugen
- *
- * @param basePath der Pfad zu Inhalten, die von diesem Handler
- * ausgeliefert werden
+ *
+ * @param basePath der Pfad zu Inhalten, die von diesem Handler ausgeliefert
+ * werden
*/
public FileHandler(String basePath) {
this.basePath = basePath;
}
/**
- * Die Datei ermitteln, die sich aus dem angefragten URL ergibt,
- * prüfen, ob die Datei existiert und den Inhalt der Datei
- * abhängig davon, ob ein Range-Header vorhanden ist,
- * ganz oder teilweise ausliefern.
- *
- * @param e das Objekt mit Methoden zur Untersuchung
- * der Anfrage sowie zum Anfertigen und Senden der Antwort
- * @throws IOException falls etwas schief geht entsteht dieser Fehler
+ * Die Datei ermitteln, die sich aus dem angefragten URL ergibt, prüfen,
+ * ob die Datei existiert und den Inhalt der Datei abhängig davon, ob ein
+ * Range-Header vorhanden ist, ganz oder teilweise ausliefern.
+ *
+ * @param e das Objekt mit Methoden zur Untersuchung der Anfrage sowie zum
+ * Anfertigen und Senden der Antwort
+ * @throws IOException falls etwas schief geht entsteht dieser Fehler
*/
@Override
public void handle(HttpExchange e) throws IOException {
String ctxPath = e.getHttpContext().getPath();
String uriPath = e.getRequestURI().getPath();
String fName = uriPath.substring(ctxPath.length());
- if(fName.startsWith(".")) {
- throw new IOException("Mit einem Punkt beginnende Dateinamen sind ungueltig.");
- }
- Headers headers = e.getRequestHeaders();
- if (headers.containsKey(RANGE_HEADER)) {
- logger.info("has range header");
- File file = new File(basePath, fName);
- logger.info(file.getAbsolutePath());
- serveFileParts(e, file);
+ if (fName.startsWith(".")) {
+ sendNotFound(e, fName);
} else {
- logger.info("no range header");
- if (fName.endsWith("/")) {
- fName += "index.html";
+ Headers headers = e.getRequestHeaders();
+ if (headers.containsKey(RANGE_HEADER)) {
+ serveFileParts(e, new File(basePath, fName));
+ } else {
+ if (fName.endsWith("/")) {
+ fName += "index.html";
+ }
+ serveFile(e, new File(basePath, fName));
}
- File file = new File(basePath, fName);
- serveFile(e, file);
}
+ }
+
+ public void sendNotFound(HttpExchange e, String fname) throws IOException {
+ OutputStream os = e.getResponseBody();
+ String response = fname + " not found.";
+ byte[] bytes = response.getBytes(StandardCharsets.UTF_8);
+ e.sendResponseHeaders(SC_NOT_FOUND, bytes.length);
+ os.write(bytes);
+ os.flush();
+ os.close();
}
/**
* Den Inhalt einer Datei ausliefern
- *
- * @param e das Objekt mit Methoden zur Untersuchung
- * der Anfrage sowie zum Anfertigen und Senden der Antwort
+ *
+ * @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
+ * @throws IOException falls etwas schief geht entsteht dieser Fehler
*/
private void serveFile(HttpExchange e, File file) throws IOException {
- OutputStream os = e.getResponseBody();
if (file.exists()) {
- e.sendResponseHeaders(200, file.length());
+ OutputStream os = e.getResponseBody();
+ e.sendResponseHeaders(SC_OK, file.length());
InputStream in = new FileInputStream(file);
int b = in.read();
while (b > -1) {
@@ -117,92 +128,101 @@
b = in.read();
}
in.close();
+ os.flush();
+ os.close();
} else {
+ sendNotFound(e, file.getName());
+ /*
String response = file.getName() + " not found.";
byte[] bytes = response.getBytes(StandardCharsets.UTF_8);
- e.sendResponseHeaders(404, bytes.length);
+ e.sendResponseHeaders(SC_NOT_FOUND, bytes.length);
os.write(bytes);
+ */
}
- os.flush();
- os.close();
}
-
+
/**
* Einen Teil des Inhalts einer Datei ausliefern
- *
- * @param e das Objekt mit Methoden zur Untersuchung
- * der Anfrage sowie zum Anfertigen und Senden der Antwort
+ *
+ * Wenn eine Range angefragt wird, hat die Antwort einen Content-Range Header
+ * wie folgt:
+ *
+ * <code>
+ * Content-Range: bytes 0-1023/146515
+ * Content-Length: 1024
+ * </code>
+ *
+ * Wenn mehrere Ranges angefragt werden, hat die Antwort mehrere Content-Range
+ * Header als Multipart Response. Multipart Responses fehlen dieser
+ * Implementierung noch.
+ *
+ * (vgl. https://developer.mozilla.org/en-US/docs/Web/HTTP/Range_requests)
+ *
+ * @param e das Objekt mit Methoden zur Untersuchung der Anfrage sowie zum
+ * Anfertigen und Senden der Antwort
* @param file die Datei, deren Inhalt teilweise ausgeliefert werden soll
- * @throws IOException falls etwas schief geht entsteht dieser Fehler
+ * @throws IOException falls etwas schief geht entsteht dieser Fehler
*/
/*
- Wenn eine Range angefragt wird, hat die Antwort einen
- Content-Range Header wie folgt:
-
- Content-Range: bytes 0-1023/146515
- Content-Length: 1024
-
- Wenn mehrere Ranges angefragt werden, hat die Antwort mehrere
- Content-Range Header als Multipart Response. Multipart Responses fehlen
- dieser Implementierung noch.
-
- (vgl. https://developer.mozilla.org/en-US/docs/Web/HTTP/Range_requests)
- */
+ */
private void serveFileParts(HttpExchange e, File file) throws IOException {
- InputStream is = new FileInputStream(file);
- OutputStream os = e.getResponseBody();
- Headers resHeaders = e.getResponseHeaders();
- long responseLength = 0;
- long start = 0;
- long end;
- RangeGroup rangeGroup = parseRanges(e, file);
- Iterator<Range> i = rangeGroup.getRanges();
- while(i.hasNext()) {
- Range range = i.next();
- start = range.getStart();
- end = range.getEnd();
- StringBuilder sb = new StringBuilder();
- sb.append("bytes ");
- sb.append(range.getStart());
- sb.append("-");
- sb.append(range.getEnd());
- sb.append("/");
- sb.append(file.length());
- resHeaders.add(CONTENT_RANGE_HEADER, sb.toString());
- logger.info(sb.toString());
- responseLength += (end - start);
- logger.info("responseLength: " + responseLength);
+ if (file.exists()) {
+ InputStream is = new FileInputStream(file);
+ OutputStream os = e.getResponseBody();
+ Headers resHeaders = e.getResponseHeaders();
+ long responseLength = 0;
+ long start = 0;
+ long end;
+ RangeGroup rangeGroup = parseRanges(e, file);
+ Iterator<Range> i = rangeGroup.getRanges();
+ while (i.hasNext()) {
+ Range range = i.next();
+ start = range.getStart();
+ end = range.getEnd();
+ StringBuilder sb = new StringBuilder();
+ sb.append("bytes ");
+ sb.append(range.getStart());
+ sb.append("-");
+ sb.append(range.getEnd());
+ sb.append("/");
+ sb.append(file.length());
+ resHeaders.add(CONTENT_RANGE_HEADER, sb.toString());
+ logger.info(sb.toString());
+ responseLength += (end - start);
+ logger.info("responseLength: " + responseLength);
+ }
+ resHeaders.add(CONTENT_TYPE, "video/mp4");
+ SimpleDateFormat sdf = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz");
+ Date date = new Date(file.lastModified());
+ resHeaders.add(LAST_MODIFIED_DATE_HEADER, sdf.format(date));
+ e.sendResponseHeaders(SC_PARTIAL_CONTENT, responseLength);
+ if (start > 0) {
+ is.skip(start);
+ }
+ long count = 0;
+ int byteRead = is.read();
+ while (byteRead > -1 && count < responseLength) {
+ ++count;
+ os.write(byteRead);
+ byteRead = is.read();
+ }
+ os.flush();
+ os.close();
+ is.close();
+ } else {
+ sendNotFound(e, file.getName());
}
- resHeaders.add(CONTENT_TYPE, "video/mp4");
- SimpleDateFormat sdf = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz");
- Date date = new Date(file.lastModified());
- resHeaders.add(LAST_MODIFIED_DATE_HEADER, sdf.format(date));
- e.sendResponseHeaders(SC_PARTIAL_CONTENT, responseLength);
- if(start > 0) {
- is.skip(start);
- }
- long count = 0;
- int byteRead = is.read();
- while(byteRead > -1 && count < responseLength) {
- ++count;
- os.write(byteRead);
- byteRead = is.read();
- }
- os.flush();
- os.close();
- is.close();
}
-
+
/**
* Die Byte-Ranges aus dem Range-Header ermitteln.
- *
+ *
* Der Range-Header kann unterschiedliche Abschnitte bezeichnen, Beispiele:
- * Range: bytes=200-1000, 2000-6576, 19000-
- * Range: bytes=0-499, -500
- * (vgl. https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Range)
- *
- * @param e das Objekt mit Methoden zur Untersuchung
- * der Anfrage sowie zum Anfertigen und Senden der Antwort
+ * Range: bytes=200-1000, 2000-6576, 19000- Range: bytes=0-499, -500 (vgl.
+ * https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Range)
+ *
+ * @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
* @return die angefragten Byte-Ranges
*/
@@ -221,10 +241,10 @@
Der regulaere Ausdruck "[^\\d-,]" bezeichnet alle Zeichen, die keine
Ziffern 0-9, Bindestrich oder Komma sind.
- */
+ */
rangeHeader = rangeHeader.replaceAll("[^\\d-,]", "");
logger.info(rangeHeader);
-
+
/*
Die Ranges ermitteln.
@@ -242,17 +262,17 @@
values.length < 2: Fall 3 ist gegeben
values.length > 1 und values[0].length < 1: Fall 1 ist gegeben
ansonsten: Fall 2 ist gegeben
- */
+ */
String[] rangeArray = rangeHeader.split(",");
- for(String rangeStr : rangeArray) {
+ for (String rangeStr : rangeArray) {
Range range = new Range();
String[] values = rangeStr.split("-");
- if(values.length < 2) {
+ if (values.length < 2) {
// Fall 3
range.setStart(Long.parseLong(values[0]));
range.setEnd(file.length());
} else {
- if(values[0].length() < 1) {
+ if (values[0].length() < 1) {
// Fall 1
range.setStart(0);
range.setEnd(Long.parseLong(values[1]));
@@ -263,19 +283,21 @@
}
}
ranges.addRange(range);
- }
+ }
return ranges;
}
-
+
/**
* Eine Range
*/
class Range {
+
private long start;
private long end;
/**
* Den Beginn dieser Range ermitteln
+ *
* @return Beginn dieser Range
*/
public long getStart() {
@@ -284,6 +306,7 @@
/**
* Den Beginn dieser Range angeben
+ *
* @param start Beginn dieser Range
*/
public void setStart(long start) {
@@ -292,6 +315,7 @@
/**
* Das Ende dieser Range ermitteln
+ *
* @return Ende dieser Range
*/
public long getEnd() {
@@ -300,49 +324,52 @@
/**
* Das Ende dieser Range angeben
+ *
* @param end Ende dieser Range
*/
public void setEnd(long end) {
this.end = end;
}
}
-
+
/**
* Eine Gruppe aus Ranges
*/
class RangeGroup {
+
private List<Range> ranges;
private long totalSize;
-
+
/**
* Ein neues Objekt der Klasse RangeGroup erzeugen
*/
public RangeGroup() {
ranges = new ArrayList();
}
-
+
/**
* Dieser RangeGroup eine Range hinzufuegen.
- *
+ *
* @param range die Range, die dieser RangeGroup hinzugefuegt werden soll
*/
public void addRange(Range range) {
ranges.add(range);
totalSize += range.getEnd() - range.getStart();
}
-
+
/**
- * Die Gesamtgröße dieser RangeGroup ermitteln, also die
- * Summe der Anzahl von Bytes aller ihrer Ranges.
- *
+ * Die Gesamtgröße dieser RangeGroup ermitteln, also die Summe
+ * der Anzahl von Bytes aller ihrer Ranges.
+ *
* @return die Größe dieser RangeGroup in Bytes
*/
public long getSize() {
return totalSize;
}
-
+
/**
* Einen Iterator über die Ranges dieser RangeGroup abrufen
+ *
* @return Iterator über die Ranges dieser RangeGroup
*/
public Iterator<Range> getRanges() {
diff --git a/src/de/uhilger/minsrv/handler/StopServerHandler.java b/src/de/uhilger/minsrv/handler/StopServerHandler.java
index 93331fe..52f2d94 100644
--- a/src/de/uhilger/minsrv/handler/StopServerHandler.java
+++ b/src/de/uhilger/minsrv/handler/StopServerHandler.java
@@ -27,7 +27,7 @@
/**
*
- * @author ulrich
+ * @author Ulrich Hilger
*/
public class StopServerHandler implements HttpHandler {
--
Gitblit v1.9.3