Ultrakompakter HTTP Server
ulrich
2024-12-01 675190608e81f38a713c965071c36b49b0ef8027
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
/*
  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 <https://www.gnu.org/licenses/>.
 */
package de.uhilger.neon;
 
import com.sun.net.httpserver.Headers;
import com.sun.net.httpserver.HttpExchange;
import java.io.File;
import java.io.IOException;
 
/**
 * Objekte der Klasse FileServer liefern Dateien ueber HTTP aus
 * 
 * Im Attribut FileServer.ATTR_FILE_BASE in 
 * HttpExchange.getContext().getAttributes() wird das 
 * Verzeichnis erwartet, aus dem Dateien ausgeliefert 
 * werden sollen. 
 * 
 * Im Attribut FileServer.ATTR_WELCOME_FILES in 
 * HttpExchange.getContext().getAttributes() kann eine 
 * mit Komma getrennte Liste mit Dateinamen uebergeben 
 * werden, die ausgeliefert werden sollen, wenn ein 
 * Verzeichnis anstelle einer Datei angefragt ist. 
 * 
 * @author Ulrich Hilger
 */
public class FileServer {
  
  public static final String RANGE_HEADER = "Range";
  
  public static final String ATTR_FILE_BASE = "fileBase";
  public static final String ATTR_WELCOME_FILES = "welcomeFiles";
 
  public static final String DEFAULT_INDEX_FILE = "index.html";
  
  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_EMPTY = "";
  public static final String STR_EQUAL = "=";
  
  public void serveFile(HttpExchange exchange) throws IOException {
    String fName = exchange.getRequestURI().getPath();
    try {
      fName = new HttpHelper().getFileName(exchange);
      String fBase = (String) exchange
              .getHttpContext().getAttributes()
              .getOrDefault(ATTR_FILE_BASE, STR_EMPTY);
      //File fileToDeliver = new File((String) exchange
         //     .getHttpContext().getAttributes()
           //   .getOrDefault(ATTR_FILE_BASE, STR_EMPTY), fName);
      File fileToDeliver = new File(fBase, fName);
      Headers headers = exchange.getRequestHeaders();
      if (headers.containsKey(RANGE_HEADER)) {
        new PartialFileServer().serveFileParts(exchange, fileToDeliver);
      } else {
        if (fName.length() < 1 || fName.endsWith(STR_SLASH)) {
          File welcomeFile = tryWelcomeFiles(exchange, fName);
          if(welcomeFile != null) {
            fileToDeliver = welcomeFile;
          }
        }
        new HttpResponder().serveFile(exchange, fileToDeliver);
      }
    } catch(IllegalArgumentException ex) {
      new HttpResponder().sendNotFound(exchange, fName);
    }
  }
  
  public File tryWelcomeFiles(HttpExchange e, String fName) {
    boolean notFound = true;
    File file = null;
    String fileBase = (String) e.getHttpContext().getAttributes()
            .getOrDefault(ATTR_FILE_BASE, STR_EMPTY);
    Object welcomeFiles = e.getHttpContext().getAttributes().get(ATTR_WELCOME_FILES);
    if(welcomeFiles instanceof String) {
      String[] fileNames = welcomeFiles.toString().split(STR_COMMA);
      int i = -1;
      while(notFound && ++i < fileNames.length) {
        file = new File(fileBase, fName + fileNames[i]);
        if(file.exists()) {
          notFound = false;
        }
      }
    }
    if(notFound) {
      file = new File(fileBase, fName + DEFAULT_INDEX_FILE);
    }
    return file;
  }
}