Made use of Jetty's file handling. Reworked some classes.

This commit is contained in:
FrozenCow 2012-01-13 01:49:45 +01:00
parent 9c49054c89
commit 58f8a34b49
5 changed files with 270 additions and 88 deletions

View File

@ -7,6 +7,7 @@ import java.io.InputStream;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.URL;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
@ -72,20 +73,19 @@ import org.dynmap.permissions.BukkitPermissions;
import org.dynmap.permissions.NijikokunPermissions; import org.dynmap.permissions.NijikokunPermissions;
import org.dynmap.permissions.OpPermissions; import org.dynmap.permissions.OpPermissions;
import org.dynmap.permissions.PermissionProvider; import org.dynmap.permissions.PermissionProvider;
import org.eclipse.jetty.server.Server; import org.dynmap.web.*;
import org.eclipse.jetty.servlet.FilterHolder; import org.eclipse.jetty.server.*;
import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.server.handler.*;
import org.eclipse.jetty.servlet.ServletHandler;
import org.eclipse.jetty.servlet.ServletHolder; import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.util.resource.FileResource;
import javax.servlet.*; import javax.servlet.*;
import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletResponse;
public class DynmapPlugin extends JavaPlugin implements DynmapAPI { public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
private String version; private String version;
private Server webServer = null; private Server webServer = null;
private ServletContextHandler webServerContextHandler = null; private HandlerRouter router = null;
public MapManager mapManager = null; public MapManager mapManager = null;
public PlayerList playerList; public PlayerList playerList;
public ConfigurationNode configuration; public ConfigurationNode configuration;
@ -409,113 +409,68 @@ public class DynmapPlugin extends JavaPlugin implements DynmapAPI {
return config_hashcode; return config_hashcode;
} }
private FileResource createFileResource(String path) {
try {
return new FileResource(new URL("file://" + path));
} catch(Exception e) {
Log.info("Could not create file resource");
return null;
}
}
public void loadWebserver() { public void loadWebserver() {
webServer = new Server(new InetSocketAddress(configuration.getString("webserver-bindaddress", "0.0.0.0"), configuration.getInteger("webserver-port", 8123))); webServer = new Server(new InetSocketAddress(configuration.getString("webserver-bindaddress", "0.0.0.0"), configuration.getInteger("webserver-port", 8123)));
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
context.setContextPath("/");
webServer.setHandler(context);
webServerContextHandler = context;
boolean allow_symlinks = configuration.getBoolean("allow-symlinks", false); final boolean allow_symlinks = configuration.getBoolean("allow-symlinks", false);
int maxconnections = configuration.getInteger("max-sessions", 30); int maxconnections = configuration.getInteger("max-sessions", 30);
if(maxconnections < 2) maxconnections = 2; if(maxconnections < 2) maxconnections = 2;
final ContextHandler context = new ContextHandler() {{
this.setContextPath("/");
this.setClassLoader(Thread.currentThread().getContextClassLoader());
this.setHandler(router = new HandlerRouter() {{
this.addHandler("/", new ResourceHandler() {{
this.setAliases(allow_symlinks);
this.setWelcomeFiles(new String[] { "index.html" });
this.setDirectoriesListed(true);
this.setBaseResource(createFileResource(getFile(getWebPath()).getAbsolutePath()));
}});
this.addHandler("/tiles/", new ResourceHandler() {{
this.setAliases(allow_symlinks);
this.setDirectoriesListed(true);
this.setBaseResource(createFileResource(tilesDirectory.toString()));
}});
}});
}};
if(allow_symlinks) if(allow_symlinks)
Log.verboseinfo("Web server is permitting symbolic links"); Log.verboseinfo("Web server is permitting symbolic links");
else else
Log.verboseinfo("Web server is not permitting symbolic links"); Log.verboseinfo("Web server is not permitting symbolic links");
org.eclipse.jetty.server.Server s = new org.eclipse.jetty.server.Server(); List<Filter> filters = new LinkedList<Filter>();
ServletHandler handler = new org.eclipse.jetty.servlet.ServletHandler();
s.setHandler(handler);
/* Check for banned IPs */ /* Check for banned IPs */
boolean checkbannedips = configuration.getBoolean("check-banned-ips", true); boolean checkbannedips = configuration.getBoolean("check-banned-ips", true);
if (checkbannedips) { if (checkbannedips) {
context.addFilter(new FilterHolder(new Filter() { filters.add(new BanIPFilter(this));
private HashSet<String> banned_ips = new HashSet<String>();
private HashSet<String> banned_ips_notified = new HashSet<String>();
private long last_loaded = 0;
private long lastmod = 0;
private static final long BANNED_RELOAD_INTERVAL = 15000; /* Every 15 seconds */
@Override
public void init(FilterConfig filterConfig) throws ServletException { }
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletResponse resp = (HttpServletResponse)response;
String ipaddr = request.getRemoteAddr();
if (isIpBanned(ipaddr)) {
Log.info("Rejected connection by banned IP address - " + ipaddr);
resp.sendError(403);
} else {
chain.doFilter(request, response);
}
}
private void loadBannedIPs() {
banned_ips.clear();
banned_ips_notified.clear();
banned_ips.addAll(getServer().getIPBans());
}
/* Return true if address is banned */
public boolean isIpBanned(String ipaddr) {
long t = System.currentTimeMillis();
if((t < last_loaded) || ((t-last_loaded) > BANNED_RELOAD_INTERVAL)) {
loadBannedIPs();
last_loaded = t;
}
if(banned_ips.contains(ipaddr)) {
if(!banned_ips_notified.contains(ipaddr)) {
banned_ips_notified.add(ipaddr);
}
return true;
}
return false;
}
@Override
public void destroy() { }
}), "/*", null);
} }
/* Load customized response headers, if any */ /* Load customized response headers, if any */
final ConfigurationNode custhttp = configuration.getNode("http-response-headers"); filters.add(new CustomHeaderFilter(configuration.getNode("http-response-headers")));
context.addFilter(new FilterHolder(new Filter() {
@Override
public void init(FilterConfig filterConfig) throws ServletException { }
@Override webServer.setHandler(/*new FilterHandler(*/context/*, filters)*/);
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletResponse resp = (HttpServletResponse)response;
if(custhttp != null) {
for(String k : custhttp.keySet()) {
String v = custhttp.getString(k);
if(v != null) {
resp.setHeader(k, v);
}
}
}
chain.doFilter(request, response);
}
@Override
public void destroy() { }
}), "/*", null);
addServlet("/*", new org.dynmap.servlet.FileServlet(getFile(getWebPath()).getAbsolutePath(), allow_symlinks));
addServlet("/tiles/*", new org.dynmap.servlet.FileServlet(tilesDirectory.getAbsolutePath(), allow_symlinks));
addServlet("/up/configuration", new org.dynmap.servlet.ClientConfigurationServlet(this)); addServlet("/up/configuration", new org.dynmap.servlet.ClientConfigurationServlet(this));
} }
public Set<String> getIPBans() {
return getServer().getIPBans();
}
public void addServlet(String path, HttpServlet servlet) { public void addServlet(String path, HttpServlet servlet) {
ServletHolder holder = new ServletHolder(servlet); ServletHolder holder = new ServletHolder(servlet);
webServerContextHandler.getServletHandler().addServletWithMapping(holder, path); router.addServlet(path, servlet);
} }

View File

@ -0,0 +1,62 @@
package org.dynmap.web;
import org.dynmap.DynmapPlugin;
import org.dynmap.Log;
import javax.servlet.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashSet;
public class BanIPFilter implements Filter {
private DynmapPlugin plugin;
private HashSet<String> banned_ips = new HashSet<String>();
private HashSet<String> banned_ips_notified = new HashSet<String>();
private long last_loaded = 0;
private long lastmod = 0;
private static final long BANNED_RELOAD_INTERVAL = 15000; /* Every 15 seconds */
public BanIPFilter(DynmapPlugin plugin) {
this.plugin = plugin;
}
@Override
public void init(FilterConfig filterConfig) throws ServletException { }
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletResponse resp = (HttpServletResponse)response;
String ipaddr = request.getRemoteAddr();
if (isIpBanned(ipaddr)) {
Log.info("Rejected connection by banned IP address - " + ipaddr);
resp.sendError(403);
} else {
chain.doFilter(request, response);
}
}
private void loadBannedIPs() {
banned_ips.clear();
banned_ips_notified.clear();
banned_ips.addAll(plugin.getIPBans());
}
/* Return true if address is banned */
public boolean isIpBanned(String ipaddr) {
long t = System.currentTimeMillis();
if((t < last_loaded) || ((t-last_loaded) > BANNED_RELOAD_INTERVAL)) {
loadBannedIPs();
last_loaded = t;
}
if(banned_ips.contains(ipaddr)) {
if(!banned_ips_notified.contains(ipaddr)) {
banned_ips_notified.add(ipaddr);
}
return true;
}
return false;
}
@Override
public void destroy() { }
}

View File

@ -0,0 +1,38 @@
package org.dynmap.web;
import org.dynmap.ConfigurationNode;
import javax.servlet.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class CustomHeaderFilter implements Filter {
private final ConfigurationNode custhttp;
public CustomHeaderFilter(ConfigurationNode configuration) {
this.custhttp = configuration;
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletResponse resp = (HttpServletResponse) response;
if (custhttp != null) {
for (String k : custhttp.keySet()) {
String v = custhttp.getString(k);
if (v != null) {
resp.setHeader(k, v);
}
}
}
chain.doFilter(request, response);
}
@Override
public void destroy() {
}
}

View File

@ -0,0 +1,67 @@
package org.dynmap.web;
import org.dynmap.Log;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.servlet.FilterHolder;
import org.eclipse.jetty.servlet.ServletContextHandler;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
public class FilterHandler extends AbstractHandler {
private Handler handler;
private LinkedList<FilterHolder> filters = new LinkedList<FilterHolder>();
public FilterHandler() {
}
public FilterHandler(Handler handler, Iterable<Filter> filters) {
this.handler = handler;
for(Filter f : filters) {
this.filters.add(new FilterHolder(f));
}
}
public Handler getHandler() {
return handler;
}
public void setHandler(Handler handler) {
this.handler = handler;
}
public Iterable<FilterHolder> getFilters() {
return filters;
}
public void addFilter(Filter filter) {
filters.add(new FilterHolder(filter));
}
@Override
public void handle(final String target, final Request baseRequest, final HttpServletRequest request, final HttpServletResponse response) throws IOException, ServletException {
final Handler handler = this.getHandler();
final Iterator<FilterHolder> iterator = getFilters().iterator();
Log.info("Filtering..." + request.getPathInfo());
final FilterChain chain = new FilterChain() {
@Override
public void doFilter(ServletRequest re, ServletResponse rs) throws IOException, ServletException {
if (iterator.hasNext()) {
Filter f = iterator.next().getFilter();
f.doFilter(request, response, this);
} else {
Log.info("Handling...");
handler.handle(target, baseRequest, request, response);
}
}
};
chain.doFilter(request, response);
}
}

View File

@ -0,0 +1,60 @@
package org.dynmap.web;
import org.dynmap.Log;
import org.eclipse.jetty.http.PathMap;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.AbstractHandler;
import javax.servlet.Servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class HandlerRouter extends AbstractHandler {
PathMap pathMap = new PathMap();
public HandlerRouter() {
}
public void addHandler(String path, Handler handler) {
pathMap.put(path, handler);
}
public void addServlet(String path, Servlet servlet) {
pathMap.put(path, servlet);
}
public void clear() {
pathMap.clear();
}
@Override
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
String pathInfo = request.getPathInfo();
PathMap.Entry e = pathMap.getMatch(pathInfo);
String mappedPath = e.getMapped();
String childPathInfo = pathInfo;
if (mappedPath != null) {
int i = 0;
while(i<mappedPath.length() && mappedPath.charAt(i) == pathInfo.charAt(i)){ i++; }
childPathInfo = childPathInfo.substring(i);
}
org.eclipse.jetty.server.Request r = (org.eclipse.jetty.server.Request)request;
r.setPathInfo(childPathInfo);
Object o = e.getValue();
if (o instanceof Handler) {
Handler h = (Handler)o;
h.handle(target, baseRequest, request, response);
} else if (o instanceof Servlet) {
Servlet s = (Servlet)o;
s.service(request, response);
}
r.setPathInfo(pathInfo);
}
}