Initial http-server work.

This commit is contained in:
FrozenCow 2011-02-05 04:33:27 +01:00
parent 711341ec47
commit bf0edea7e2
4 changed files with 163 additions and 40 deletions

View File

@ -0,0 +1,7 @@
package org.dynmap.web;
import java.io.IOException;
public interface HttpHandler {
void handle(String path, HttpRequest request, HttpResponse response) throws IOException;
}

View File

@ -0,0 +1,13 @@
package org.dynmap.web;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
public class HttpRequest {
public String method;
public String path;
public String version;
public Map<String, String> fields = new HashMap<String, String>();
public InputStream body;
}

View File

@ -0,0 +1,27 @@
package org.dynmap.web;
import java.io.IOException;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
public class HttpResponse {
public int statusCode = 200;
public String statusMessage = "OK";
public Map<String, String> fields = new HashMap<String, String>();
private OutputStream body;
public OutputStream getBody() throws IOException {
if (body != null) {
WebServerRequest.writeResponseHeader(body, this);
OutputStream b = body;
body = null;
return b;
}
return null;
}
public HttpResponse(OutputStream body) {
this.body = body;
}
}

View File

@ -1,5 +1,6 @@
package org.dynmap.web; package org.dynmap.web;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream; import java.io.BufferedOutputStream;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.File; import java.io.File;
@ -7,13 +8,22 @@ import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.Reader;
import java.net.Socket; import java.net.Socket;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date; import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.logging.Logger; import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
@ -33,6 +43,8 @@ public class WebServerRequest extends Thread {
private World world; private World world;
private PlayerList playerList; private PlayerList playerList;
private ConfigurationNode configuration; private ConfigurationNode configuration;
public SortedMap<String, HttpHandler> handlers = new TreeMap<String, HttpHandler>(Collections.reverseOrder());
public WebServerRequest(Socket socket, MapManager mgr, World world, PlayerList playerList, ConfigurationNode configuration, Debugger debugger) { public WebServerRequest(Socket socket, MapManager mgr, World world, PlayerList playerList, ConfigurationNode configuration, Debugger debugger) {
this.debugger = debugger; this.debugger = debugger;
@ -41,6 +53,27 @@ public class WebServerRequest extends Thread {
this.world = world; this.world = world;
this.playerList = playerList; this.playerList = playerList;
this.configuration = configuration; this.configuration = configuration;
handlers.put("/", new HttpHandler() {
@Override
public void handle(String path, HttpRequest request, HttpResponse response) throws IOException {
response.fields.put("Content-Type", "text/plain");
BufferedOutputStream s = new BufferedOutputStream(response.getBody());
s.write("Hallo".getBytes());
s.flush();
s.close();
}
});
handlers.put("/test/", new HttpHandler() {
@Override
public void handle(String path, HttpRequest request, HttpResponse response) throws IOException {
response.fields.put("Content-Type", "text/plain");
BufferedOutputStream s = new BufferedOutputStream(response.getBody());
s.write("test".getBytes());
s.flush();
s.close();
}
});
} }
private static void writeHttpHeader(BufferedOutputStream out, int statusCode, String statusText) throws IOException { private static void writeHttpHeader(BufferedOutputStream out, int statusCode, String statusText) throws IOException {
@ -63,24 +96,90 @@ public class WebServerRequest extends Thread {
out.write(10); out.write(10);
} }
private static Pattern requestHeaderLine = Pattern.compile("^(\\S+)\\s+(\\S+)\\s+HTTP/(.+)$");
private static Pattern requestHeaderField = Pattern.compile("^([^:]+):\\s*(.+)$");
private static boolean readRequestHeader(InputStream in, HttpRequest request) throws IOException {
BufferedReader r = new BufferedReader(new InputStreamReader(in));
Matcher m = requestHeaderLine.matcher(r.readLine());
if (!m.matches())
return false;
request.method = m.group(1);
request.path = m.group(2);
request.version = m.group(3);
String line;
while((line = r.readLine()) != null) {
log.info("Header line: " + line);
if (line.equals(""))
break;
m = requestHeaderField.matcher(line);
// Warning: unknown lines are ignored.
if (m.matches()) {
String fieldName = m.group(1);
String fieldValue = m.group(2);
// TODO: Does not support duplicate field-names.
request.fields.put(fieldName, fieldValue);
}
}
return true;
}
public static void writeResponseHeader(OutputStream out, HttpResponse response) throws IOException {
BufferedOutputStream o = new BufferedOutputStream(out);
StringBuilder sb = new StringBuilder();
sb.append(response.statusCode);
sb.append(" ");
sb.append(response.statusMessage);
sb.append("\n");
for(Entry<String,String> field : response.fields.entrySet()) {
sb.append(field.getKey());
sb.append(": ");
sb.append(field.getValue());
sb.append("\n");
}
sb.append("\n");
o.write(sb.toString().getBytes());
}
public void run() { public void run() {
BufferedReader in = null;
BufferedOutputStream out = null;
try { try {
socket.setSoTimeout(30000); socket.setSoTimeout(30000);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = new BufferedOutputStream(socket.getOutputStream());
String request = in.readLine(); HttpRequest request = new HttpRequest();
if (request == null || !request.startsWith("GET ") || !(request.endsWith(" HTTP/1.0") || request.endsWith("HTTP/1.1"))) { log.info("Reading request...");
// Invalid request type (no "GET") if (!readRequestHeader(socket.getInputStream(), request)) {
writeHttpHeader(out, 500, "Invalid Method."); log.info("Invalid request header, aborting...");
writeEndOfHeaders(out); socket.close();
return; return;
} }
String path = request.substring(4, request.length() - 9); // TODO: Optimize HttpHandler-finding by using a real path-aware tree.
debugger.debug("request: " + path); HttpResponse response = null;
for(Entry<String, HttpHandler> entry : handlers.entrySet()) {
String key = entry.getKey();
boolean directoryHandler = key.endsWith("/");
if (directoryHandler && request.path.startsWith(entry.getKey()) ||
!directoryHandler && request.path.equals(entry.getKey())) {
String path = request.path.substring(entry.getKey().length());
response = new HttpResponse(socket.getOutputStream());
entry.getValue().handle(path, request, response);
break;
}
}
if (response != null) {
String connection = response.fields.get("Connection");
if (connection != null && connection.equals("close")) {
socket.close();
return;
}
} else {
log.info("No handler found");
socket.close();
return;
}
/*debugger.debug("request: " + path);
if (path.equals("/up/configuration")) { if (path.equals("/up/configuration")) {
handleConfiguration(out); handleConfiguration(out);
} else if (path.startsWith("/up/")) { } else if (path.startsWith("/up/")) {
@ -89,36 +188,13 @@ public class WebServerRequest extends Thread {
handleMapToDirectory(out, path.substring(6), mgr.tileDirectory); handleMapToDirectory(out, path.substring(6), mgr.tileDirectory);
} else if (path.startsWith("/")) { } else if (path.startsWith("/")) {
handleMapToDirectory(out, path, mgr.webDirectory); handleMapToDirectory(out, path, mgr.webDirectory);
} }*/
out.flush();
out.close();
} catch (IOException e) { } catch (IOException e) {
if (out != null) { try { socket.close(); } catch(IOException ex) { }
try { } catch (Exception e) {
out.close(); try { socket.close(); } catch(IOException ex) { }
} catch (Exception anye) { debugger.error("Exception on WebRequest-thread: " + e.toString());
} e.printStackTrace();
}
if (in != null) {
try {
in.close();
} catch (Exception anye) {
}
}
} catch (Exception ex) {
if (out != null) {
try {
out.close();
} catch (Exception anye) {
}
}
if (in != null) {
try {
in.close();
} catch (Exception anye) {
}
}
debugger.error("Exception on WebRequest-thread: " + ex.toString());
} }
} }