diff options
Diffstat (limited to 'webserver/src/main/java/fi/iki/elonen')
-rw-r--r-- | webserver/src/main/java/fi/iki/elonen/SimpleWebServer.java | 73 |
1 files changed, 62 insertions, 11 deletions
diff --git a/webserver/src/main/java/fi/iki/elonen/SimpleWebServer.java b/webserver/src/main/java/fi/iki/elonen/SimpleWebServer.java index f3ad1c2..f5415d6 100644 --- a/webserver/src/main/java/fi/iki/elonen/SimpleWebServer.java +++ b/webserver/src/main/java/fi/iki/elonen/SimpleWebServer.java @@ -32,7 +32,6 @@ package fi.iki.elonen; * OF THE POSSIBILITY OF SUCH DAMAGE. * #L% */ - import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; @@ -138,6 +137,7 @@ public class SimpleWebServer extends NanoHTTPD { String host = null; // bind to all interfaces by default List<File> rootDirs = new ArrayList<File>(); boolean quiet = false; + String cors = null; Map<String, String> options = new HashMap<String, String>(); // Parse command-line, with short and long versions of the options. @@ -150,6 +150,12 @@ public class SimpleWebServer extends NanoHTTPD { quiet = true; } else if (args[i].equalsIgnoreCase("-d") || args[i].equalsIgnoreCase("--dir")) { rootDirs.add(new File(args[i + 1]).getAbsoluteFile()); + } else if (args[i].startsWith("--cors")) { + cors = "*"; + int equalIdx = args[i].indexOf('='); + if (equalIdx > 0) { + cors = args[i].substring(equalIdx + 1); + } } else if (args[i].equalsIgnoreCase("--licence")) { System.out.println(SimpleWebServer.LICENCE + "\n"); } else if (args[i].startsWith("-X:")) { @@ -165,7 +171,6 @@ public class SimpleWebServer extends NanoHTTPD { if (rootDirs.isEmpty()) { rootDirs.add(new File(".").getAbsoluteFile()); } - options.put("host", host); options.put("port", "" + port); options.put("quiet", String.valueOf(quiet)); @@ -180,7 +185,6 @@ public class SimpleWebServer extends NanoHTTPD { } } options.put("home", sb.toString()); - ServiceLoader<WebServerPluginInfo> serviceLoader = ServiceLoader.load(WebServerPluginInfo.class); for (WebServerPluginInfo info : serviceLoader) { String[] mimeTypes = info.getMimeTypes(); @@ -199,8 +203,7 @@ public class SimpleWebServer extends NanoHTTPD { registerPluginForMimeType(indexFiles, mime, info.getWebServerPlugin(mime), options); } } - - ServerRunner.executeInstance(new SimpleWebServer(host, port, rootDirs, quiet)); + ServerRunner.executeInstance(new SimpleWebServer(host, port, rootDirs, quiet, cors)); } protected static void registerPluginForMimeType(String[] indexFiles, String mimeType, WebServerPlugin plugin, Map<String, String> commandLineOptions) { @@ -224,20 +227,26 @@ public class SimpleWebServer extends NanoHTTPD { private final boolean quiet; + private final String cors; + protected List<File> rootDirs; - public SimpleWebServer(String host, int port, File wwwroot, boolean quiet) { - super(host, port); - this.quiet = quiet; - this.rootDirs = new ArrayList<File>(); - this.rootDirs.add(wwwroot); + public SimpleWebServer(String host, int port, File wwwroot, boolean quiet, String cors) { + this(host, port, Collections.singletonList(wwwroot), quiet, cors); + } - init(); + public SimpleWebServer(String host, int port, File wwwroot, boolean quiet) { + this(host, port, Collections.singletonList(wwwroot), quiet, null); } public SimpleWebServer(String host, int port, List<File> wwwroots, boolean quiet) { + this(host, port, wwwroots, quiet, null); + } + + public SimpleWebServer(String host, int port, List<File> wwwroots, boolean quiet, String cors) { super(host, port); this.quiet = quiet; + this.cors = cors; this.rootDirs = new ArrayList<File>(wwwroots); init(); @@ -394,6 +403,21 @@ public class SimpleWebServer extends NanoHTTPD { } private Response respond(Map<String, String> headers, IHTTPSession session, String uri) { + // First let's handle CORS OPTION query + Response r; + if (cors != null && Method.OPTIONS.equals(session.getMethod())) { + r = new NanoHTTPD.Response(Response.Status.OK, MIME_PLAINTEXT, null, 0); + } else { + r = defaultRespond(headers, session, uri); + } + + if (cors != null) { + r = addCORSHeaders(headers, r, cors); + } + return r; + } + + private Response defaultRespond(Map<String, String> headers, IHTTPSession session, String uri) { // Remove URL arguments uri = uri.trim().replace(File.separatorChar, '/'); if (uri.indexOf('?') >= 0) { @@ -596,4 +620,31 @@ public class SimpleWebServer extends NanoHTTPD { res.addHeader("Accept-Ranges", "bytes"); return res; } + + protected Response addCORSHeaders(Map<String, String> queryHeaders, Response resp, String cors) { + resp.addHeader("Access-Control-Allow-Origin", cors); + resp.addHeader("Access-Control-Allow-Headers", calculateAllowHeaders(queryHeaders)); + resp.addHeader("Access-Control-Allow-Credentials", "true"); + resp.addHeader("Access-Control-Allow-Methods", ALLOWED_METHODS); + resp.addHeader("Access-Control-Max-Age", "" + MAX_AGE); + + return resp; + } + + private String calculateAllowHeaders(Map<String, String> queryHeaders) { + // here we should use the given asked headers + // but NanoHttpd uses a Map whereas it is possible for requester to send + // several time the same header + // let's just use default values for this version + return System.getProperty(ACCESS_CONTROL_ALLOW_HEADER_PROPERTY_NAME, DEFAULT_ALLOWED_HEADERS); + } + + private final static String ALLOWED_METHODS = "GET, POST, PUT, DELETE, OPTIONS, HEAD"; + + private final static int MAX_AGE = 42 * 60 * 60; + + // explicitly relax visibility to package for tests purposes + final static String DEFAULT_ALLOWED_HEADERS = "origin,accept,content-type"; + + public final static String ACCESS_CONTROL_ALLOW_HEADER_PROPERTY_NAME = "AccessControlAllowHeader"; } |