Basisklassen zum Modul jdk.httpserver
ulrich
2021-06-16 9efb60a4946b01a72e292b65a1cf968e9f758e74
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/*
  http-base - Extensions to jdk.httpserver
  Copyright (C) 2021  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 <https://www.gnu.org/licenses/>.
 */
package de.uhilger.httpserver.base.handler;
 
import de.uhilger.httpserver.base.HttpResponder;
import com.sun.net.httpserver.Headers;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import de.uhilger.httpserver.base.actor.FileActor;
import java.io.File;
import java.io.IOException;
import java.util.logging.Logger;
 
/**
 * Die Klasse FileHandler dient zur Auslieferung von Dateiinhalten &uuml;ber
 * HTTP.
 *
 * F&uuml;r das Streaming &uuml;ber HTTP wird die Auslieferung von Teilinhalten
 * mit dem Accept-Ranges-Header angeboten und via Range-Header unterst&uuml;tzt.
 * (vgl. https://developer.mozilla.org/en-US/docs/Web/HTTP/Range_requests)
 *
 * @author Ulrich Hilger
 * @version 1, 03.06.2021, (seit 25. M&auml;rz 2021)
 */
public class FileHandler implements HttpHandler {
 
  /* Der Logger fuer diesen FileHandler */
  private static final Logger logger = Logger.getLogger(FileHandler.class.getName());
 
  /* Headernamen */
  public static final String RANGE_HEADER = "Range";
  public static final String CONTENT_RANGE_HEADER = "Content-Range";
  //public static final String ACCEPT_RANGES_HEADER = "Accept-Ranges";
  //public static final String LAST_MODIFIED_DATE_HEADER = "Last-Modified";
  public static final String CONTENT_TYPE = "Content-Type";
  public static final String CONTENT_LENGTH = "Content-Length";
 
  /* Statuscodes */
  public static final int SC_OK = 200;
  public static final int SC_PARTIAL_CONTENT = 206;
  public static final int SC_FORBIDDEN = 403;
  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;
 
  /* String Konstanten */
  //public static final String STR_BYTES = "bytes";
  public static final String STR_SLASH = "/";
  public static final String STR_BLANK = " ";
  public static final String STR_DASH = "-";
  public static final String STR_COMMA = ",";
  public static final String STR_DOT = ".";
  //public static final String STR_NOT_FOUND = " not found.";
  //public static final String LM_PATTERN = "EEE, dd MMM yyyy HH:mm:ss zzz";
  public static final String RANGE_PATTERN = "[^\\d-,]";
  public static final String WELCOME_FILE = "index.html";
 
  /* Ablageort fuer Webinhalte */
  protected final String fileBase;
 
  /**
   * Ein neues Objekt der Klasse FileHandler erzeugen
   *
   * @param absoluteDirectoryPathAndName der absolute Pfad und Name des 
   * Ordners im Dateisystem, der die Inhalte enthaelt, die von diesem 
   * Handler ausgeliefert werden sollen
   */
  public FileHandler(String absoluteDirectoryPathAndName) {
    this.fileBase = absoluteDirectoryPathAndName;
  }
 
  /**
   * Die Datei ermitteln, die sich aus dem angefragten URL ergibt, pr&uuml;fen,
   * ob die Datei existiert und den Inhalt der Datei abh&auml;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 fName = getFileName(e);
    if (fName.startsWith(STR_DOT)) {
      HttpResponder fs = new HttpResponder();
      fs.sendNotFound(e, fName);
    } else {
      Headers headers = e.getRequestHeaders();
      if (headers.containsKey(RANGE_HEADER)) {
        FileActor fa = new FileActor();
        fa.serveFileParts(e, new File(fileBase, fName));
      } else {
        if (fName.length() < 1 || fName.endsWith(STR_SLASH)) {
          fName += WELCOME_FILE;
        }
        HttpResponder fs = new HttpResponder();
        fs.serveFile(e, new File(fileBase, fName));
      }
    }
  }
 
  /**
   * Den Namen der gew&uuml;nschten Datei aus der HTTP-Anfrage ermitteln
   * 
   * @param e das Objekt mit Methoden zur Untersuchung der Anfrage sowie zum
   * Anfertigen und Senden der Antwort
   * @return Name der gew&uuml;nschten Datei
   */
  public String getFileName(HttpExchange e) {
    String ctxPath = e.getHttpContext().getPath();
    String uriPath = e.getRequestURI().getPath();
    logger.info(uriPath);
    return uriPath.substring(ctxPath.length());
  }
  
}