diff --git a/src/main/java/org/dynmap/DynmapPlugin.java b/src/main/java/org/dynmap/DynmapPlugin.java index c85fe5da..2d651631 100644 --- a/src/main/java/org/dynmap/DynmapPlugin.java +++ b/src/main/java/org/dynmap/DynmapPlugin.java @@ -275,11 +275,13 @@ public class DynmapPlugin extends JavaPlugin { int port = configuration.getInteger("webserver-port", 8123); boolean allow_symlinks = configuration.getBoolean("allow-symlinks", false); boolean checkbannedips = configuration.getBoolean("check-banned-ips", true); + int maxconnections = configuration.getInteger("max-sessions", 30); + if(maxconnections < 2) maxconnections = 2; if(allow_symlinks) Log.verboseinfo("Web server is permitting symbolic links"); else Log.verboseinfo("Web server is not permitting symbolic links"); - webServer = new HttpServer(bindAddress, port, checkbannedips); + webServer = new HttpServer(bindAddress, port, checkbannedips, maxconnections); webServer.handlers.put("/", new FilesystemHandler(getFile(configuration.getString("webpath", "web")), allow_symlinks)); webServer.handlers.put("/tiles/", new FilesystemHandler(tilesDirectory, allow_symlinks)); webServer.handlers.put("/up/configuration", new ClientConfigurationHandler(this)); diff --git a/src/main/java/org/dynmap/web/HttpServer.java b/src/main/java/org/dynmap/web/HttpServer.java index d82a02ec..841dc71c 100644 --- a/src/main/java/org/dynmap/web/HttpServer.java +++ b/src/main/java/org/dynmap/web/HttpServer.java @@ -27,16 +27,19 @@ public class HttpServer extends Thread { private InetAddress bindAddress; private int port; private boolean check_banned_ips; + private int max_sessions; public SortedMap handlers = new TreeMap(Collections.reverseOrder()); private Object lock = new Object(); private HashSet active_connections = new HashSet(); + private HashSet keepalive_connections = new HashSet(); - public HttpServer(InetAddress bindAddress, int port, boolean check_banned_ips) { + public HttpServer(InetAddress bindAddress, int port, boolean check_banned_ips, int max_sessions) { this.bindAddress = bindAddress; this.port = port; this.check_banned_ips = check_banned_ips; + this.max_sessions = max_sessions; } public InetAddress getAddress() { @@ -68,8 +71,13 @@ public class HttpServer extends Thread { HttpServerConnection requestThread = new HttpServerConnection(socket, this); synchronized(lock) { active_connections.add(requestThread); + requestThread.start(); + /* If we're at limit, wait here until we're free to accept another */ + while((listeningThread == Thread.currentThread()) && + (active_connections.size() >= max_sessions)) { + lock.wait(500); + } } - requestThread.start(); } catch (IOException e) { if(listeningThread != null) /* Only report this if we didn't initiate the shutdown */ Log.info("map WebServer.run() stops with IOException"); @@ -102,10 +110,23 @@ public class HttpServer extends Thread { Log.warning("Exception while closing socket for webserver shutdown", e); } } + + public boolean canKeepAlive(HttpServerConnection c) { + synchronized(lock) { + /* If less than half of our limit are keep-alive, approve */ + if(keepalive_connections.size() < (max_sessions/2)) { + keepalive_connections.add(c); + return true; + } + } + return false; + } public void connectionEnded(HttpServerConnection c) { synchronized(lock) { active_connections.remove(c); + keepalive_connections.remove(c); + lock.notifyAll(); } } diff --git a/src/main/java/org/dynmap/web/HttpServerConnection.java b/src/main/java/org/dynmap/web/HttpServerConnection.java index 7a2afe22..5784fafe 100644 --- a/src/main/java/org/dynmap/web/HttpServerConnection.java +++ b/src/main/java/org/dynmap/web/HttpServerConnection.java @@ -26,6 +26,7 @@ public class HttpServerConnection extends Thread { private Socket socket; private HttpServer server; private boolean do_shutdown; + private boolean can_keepalive; private PrintStream printOut; private StringWriter sw = new StringWriter(); @@ -36,6 +37,7 @@ public class HttpServerConnection extends Thread { this.socket = socket; this.server = server; do_shutdown = false; + can_keepalive = false; } private final static void readLine(InputStream in, StringWriter sw) throws IOException { @@ -159,7 +161,9 @@ public class HttpServerConnection extends Thread { boolean iskeepalive = false; String keepalive = request.fields.get(HttpField.Connection); if((keepalive != null) && (keepalive.toLowerCase().indexOf("keep-alive") >= 0)) { - iskeepalive = true; + /* See if we're clear to do keepalive */ + if(!iskeepalive) + iskeepalive = server.canKeepAlive(this); } // TODO: Optimize HttpHandler-finding by using a real path-aware tree. @@ -193,6 +197,9 @@ public class HttpServerConnection extends Thread { response.fields.put(HttpField.Connection, "keep-alive"); response.fields.put("Keep-Alive", "timeout=5"); } + else { + response.fields.put(HttpField.Connection, "close"); + } try { handler.handle(relativePath, request, response); } catch (IOException e) { diff --git a/src/main/resources/configuration.txt b/src/main/resources/configuration.txt index dde8d1d1..fc23bb06 100644 --- a/src/main/resources/configuration.txt +++ b/src/main/resources/configuration.txt @@ -116,6 +116,9 @@ webserver-bindaddress: 0.0.0.0 # The TCP-port the webserver will listen on. webserver-port: 8123 +# Maximum concurrent session on internal web server - limits resources used in Bukkit server +max-sessions: 30 + # Disables Webserver portion of Dynmap (Advanced users only) disable-webserver: false