mirror of
https://github.com/webbukkit/dynmap.git
synced 2024-11-27 20:58:40 +01:00
Initial http-server work.
This commit is contained in:
parent
711341ec47
commit
bf0edea7e2
7
src/main/java/org/dynmap/web/HttpHandler.java
Normal file
7
src/main/java/org/dynmap/web/HttpHandler.java
Normal 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;
|
||||||
|
}
|
13
src/main/java/org/dynmap/web/HttpRequest.java
Normal file
13
src/main/java/org/dynmap/web/HttpRequest.java
Normal 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;
|
||||||
|
}
|
27
src/main/java/org/dynmap/web/HttpResponse.java
Normal file
27
src/main/java/org/dynmap/web/HttpResponse.java
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
@ -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());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user