From e55ac2d9e57bc5c671c7b33356e96961af916fe8 Mon Sep 17 00:00:00 2001 From: Paul Hawke Date: Sun, 5 May 2013 16:27:19 -0500 Subject: Extracted and promoted the NanoHttpd Webserver to a top-level project (instead of being a "sample"). --- .../src/main/java/fi/iki/elonen/ServerRunner.java | 32 -- .../main/java/fi/iki/elonen/SimpleWebServer.java | 323 --------------------- 2 files changed, 355 deletions(-) delete mode 100644 samples/src/main/java/fi/iki/elonen/ServerRunner.java delete mode 100644 samples/src/main/java/fi/iki/elonen/SimpleWebServer.java (limited to 'samples/src') diff --git a/samples/src/main/java/fi/iki/elonen/ServerRunner.java b/samples/src/main/java/fi/iki/elonen/ServerRunner.java deleted file mode 100644 index 313097a..0000000 --- a/samples/src/main/java/fi/iki/elonen/ServerRunner.java +++ /dev/null @@ -1,32 +0,0 @@ -package fi.iki.elonen; - -import java.io.IOException; - -public class ServerRunner { - public static void run(Class serverClass) { - try { - executeInstance((NanoHTTPD) serverClass.newInstance()); - } catch (Exception e) { - e.printStackTrace(); - } - } - - public static void executeInstance(NanoHTTPD server) { - try { - server.start(); - } catch (IOException ioe) { - System.err.println("Couldn't start server:\n" + ioe); - System.exit(-1); - } - - System.out.println("Server started, Hit Enter to stop.\n"); - - try { - System.in.read(); - } catch (Throwable ignored) { - } - - server.stop(); - System.out.println("Server stopped.\n"); - } -} diff --git a/samples/src/main/java/fi/iki/elonen/SimpleWebServer.java b/samples/src/main/java/fi/iki/elonen/SimpleWebServer.java deleted file mode 100644 index 5f0d5ad..0000000 --- a/samples/src/main/java/fi/iki/elonen/SimpleWebServer.java +++ /dev/null @@ -1,323 +0,0 @@ -package fi.iki.elonen; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; -import java.util.StringTokenizer; - -public class SimpleWebServer extends NanoHTTPD { - /** - * Hashtable mapping (String)FILENAME_EXTENSION -> (String)MIME_TYPE - */ - private static final Map MIME_TYPES; - static { - Map mime = new HashMap(); - mime.put("css", "text/css"); - mime.put("htm", "text/html"); - mime.put("html", "text/html"); - mime.put("xml", "text/xml"); - mime.put("txt", "text/plain"); - mime.put("asc", "text/plain"); - mime.put("gif", "image/gif"); - mime.put("jpg", "image/jpeg"); - mime.put("jpeg", "image/jpeg"); - mime.put("png", "image/png"); - mime.put("mp3", "audio/mpeg"); - mime.put("m3u", "audio/mpeg-url"); - mime.put("mp4", "video/mp4"); - mime.put("ogv", "video/ogg"); - mime.put("flv", "video/x-flv"); - mime.put("mov", "video/quicktime"); - mime.put("swf", "application/x-shockwave-flash"); - mime.put("js", "application/javascript"); - mime.put("pdf", "application/pdf"); - mime.put("doc", "application/msword"); - mime.put("ogg", "application/x-ogg"); - mime.put("zip", "application/octet-stream"); - mime.put("exe", "application/octet-stream"); - mime.put("class", "application/octet-stream"); - MIME_TYPES = mime; - } - - /** - * The distribution licence - */ - private static final String LICENCE = "Copyright (C) 2001,2005-2011 by Jarno Elonen \n" - + "and Copyright (C) 2010 by Konstantinos Togias \n" + "\n" - + "Redistribution and use in source and binary forms, with or without\n" - + "modification, are permitted provided that the following conditions\n" + "are met:\n" + "\n" - + "Redistributions of source code must retain the above copyright notice,\n" - + "this list of conditions and the following disclaimer. Redistributions in\n" - + "binary form must reproduce the above copyright notice, this list of\n" - + "conditions and the following disclaimer in the documentation and/or other\n" - + "materials provided with the distribution. The name of the author may not\n" - + "be used to endorse or promote products derived from this software without\n" - + "specific prior written permission. \n" - + " \n" + "THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n" - + "IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n" - + "OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n" - + "IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,\n" - + "INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n" - + "NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n" - + "DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n" - + "THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n" - + "(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n" - + "OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."; - - private File rootDir; - - public SimpleWebServer(String host, int port, File wwwroot) { - super(host, port); - this.rootDir = wwwroot; - } - - public File getRootDir() { - return rootDir; - } - - /** - * URL-encodes everything between "/"-characters. Encodes spaces as '%20' instead of '+'. - */ - private String encodeUri(String uri) { - String newUri = ""; - StringTokenizer st = new StringTokenizer(uri, "/ ", true); - while (st.hasMoreTokens()) { - String tok = st.nextToken(); - if (tok.equals("/")) - newUri += "/"; - else if (tok.equals(" ")) - newUri += "%20"; - else { - try { - newUri += URLEncoder.encode(tok, "UTF-8"); - } catch (UnsupportedEncodingException ignored) { - } - } - } - return newUri; - } - - /** - * Serves file from homeDir and its' subdirectories (only). Uses only URI, ignores all headers and HTTP parameters. - */ - public Response serveFile(String uri, Map header, File homeDir) { - Response res = null; - - // Make sure we won't die of an exception later - if (!homeDir.isDirectory()) - res = new Response(Response.Status.INTERNAL_ERROR, NanoHTTPD.MIME_PLAINTEXT, "INTERNAL ERRROR: serveFile(): given homeDir is not a directory."); - - if (res == null) { - // Remove URL arguments - uri = uri.trim().replace(File.separatorChar, '/'); - if (uri.indexOf('?') >= 0) - uri = uri.substring(0, uri.indexOf('?')); - - // Prohibit getting out of current directory - if (uri.startsWith("src/main") || uri.endsWith("src/main") || uri.contains("../")) - res = new Response(Response.Status.FORBIDDEN, NanoHTTPD.MIME_PLAINTEXT, "FORBIDDEN: Won't serve ../ for security reasons."); - } - - File f = new File(homeDir, uri); - if (res == null && !f.exists()) - res = new Response(Response.Status.NOT_FOUND, NanoHTTPD.MIME_PLAINTEXT, "Error 404, file not found."); - - // List the directory, if necessary - if (res == null && f.isDirectory()) { - // Browsers get confused without '/' after the - // directory, send a redirect. - if (!uri.endsWith("/")) { - uri += "/"; - res = new Response(Response.Status.REDIRECT, NanoHTTPD.MIME_HTML, "Redirected: " + uri - + ""); - res.addHeader("Location", uri); - } - - if (res == null) { - // First try index.html and index.htm - if (new File(f, "index.html").exists()) - f = new File(homeDir, uri + "/index.html"); - else if (new File(f, "index.htm").exists()) - f = new File(homeDir, uri + "/index.htm"); - // No index file, list the directory if it is readable - else if (f.canRead()) { - String[] files = f.list(); - String msg = "

Directory " + uri + "


"; - - if (uri.length() > 1) { - String u = uri.substring(0, uri.length() - 1); - int slash = u.lastIndexOf('/'); - if (slash >= 0 && slash < u.length()) - msg += "..
"; - } - - if (files != null) { - for (int i = 0; i < files.length; ++i) { - File curFile = new File(f, files[i]); - boolean dir = curFile.isDirectory(); - if (dir) { - msg += ""; - files[i] += "/"; - } - - msg += "" + files[i] + ""; - - // Show file size - if (curFile.isFile()) { - long len = curFile.length(); - msg += "  ("; - if (len < 1024) - msg += len + " bytes"; - else if (len < 1024 * 1024) - msg += len / 1024 + "." + (len % 1024 / 10 % 100) + " KB"; - else - msg += len / (1024 * 1024) + "." + len % (1024 * 1024) / 10 % 100 + " MB"; - - msg += ")"; - } - msg += "
"; - if (dir) - msg += "
"; - } - } - msg += ""; - res = new Response(msg); - } else { - res = new Response(Response.Status.FORBIDDEN, NanoHTTPD.MIME_PLAINTEXT, "FORBIDDEN: No directory listing."); - } - } - } - - try { - if (res == null) { - // Get MIME type from file name extension, if possible - String mime = null; - int dot = f.getCanonicalPath().lastIndexOf('.'); - if (dot >= 0) - mime = MIME_TYPES.get(f.getCanonicalPath().substring(dot + 1).toLowerCase()); - if (mime == null) - mime = NanoHTTPD.MIME_DEFAULT_BINARY; - - // Calculate etag - String etag = Integer.toHexString((f.getAbsolutePath() + f.lastModified() + "" + f.length()).hashCode()); - - // Support (simple) skipping: - long startFrom = 0; - long endAt = -1; - String range = header.get("range"); - if (range != null) { - if (range.startsWith("bytes=")) { - range = range.substring("bytes=".length()); - int minus = range.indexOf('-'); - try { - if (minus > 0) { - startFrom = Long.parseLong(range.substring(0, minus)); - endAt = Long.parseLong(range.substring(minus + 1)); - } - } catch (NumberFormatException ignored) { - } - } - } - - // Change return code and add Content-Range header when skipping is requested - long fileLen = f.length(); - if (range != null && startFrom >= 0) { - if (startFrom >= fileLen) { - res = new Response(Response.Status.RANGE_NOT_SATISFIABLE, NanoHTTPD.MIME_PLAINTEXT, ""); - res.addHeader("Content-Range", "bytes 0-0/" + fileLen); - res.addHeader("ETag", etag); - } else { - if (endAt < 0) - endAt = fileLen - 1; - long newLen = endAt - startFrom + 1; - if (newLen < 0) - newLen = 0; - - final long dataLen = newLen; - FileInputStream fis = new FileInputStream(f) { - @Override - public int available() throws IOException { - return (int) dataLen; - } - }; - fis.skip(startFrom); - - res = new Response(Response.Status.PARTIAL_CONTENT, mime, fis); - res.addHeader("Content-Length", "" + dataLen); - res.addHeader("Content-Range", "bytes " + startFrom + "-" + endAt + "/" + fileLen); - res.addHeader("ETag", etag); - } - } else { - if (etag.equals(header.get("if-none-match"))) - res = new Response(Response.Status.NOT_MODIFIED, mime, ""); - else { - res = new Response(Response.Status.OK, mime, new FileInputStream(f)); - res.addHeader("Content-Length", "" + fileLen); - res.addHeader("ETag", etag); - } - } - } - } catch (IOException ioe) { - res = new Response(Response.Status.FORBIDDEN, NanoHTTPD.MIME_PLAINTEXT, "FORBIDDEN: Reading file failed."); - } - - res.addHeader("Accept-Ranges", "bytes"); // Announce that the file server accepts partial content requestes - return res; - } - - @Override - public Response serve(String uri, Method method, Map header, Map parms, Map files) { - System.out.println(method + " '" + uri + "' "); - - Iterator e = header.keySet().iterator(); - while (e.hasNext()) { - String value = e.next(); - System.out.println(" HDR: '" + value + "' = '" + header.get(value) + "'"); - } - e = parms.keySet().iterator(); - while (e.hasNext()) { - String value = e.next(); - System.out.println(" PRM: '" + value + "' = '" + parms.get(value) + "'"); - } - e = files.keySet().iterator(); - while (e.hasNext()) { - String value = e.next(); - System.out.println(" UPLOADED: '" + value + "' = '" + files.get(value) + "'"); - } - - return serveFile(uri, header, getRootDir()); - } - - /** - * Starts as a standalone file server and waits for Enter. - */ - public static void main(String[] args) { - System.out.println("NanoHTTPD 1.25 (C) 2001,2005-2011 Jarno Elonen and (C) 2010 Konstantinos Togias\n" - + "(Command line options: [-h hostname] [-p port] [-d root-dir] [--licence])\n"); - - // Defaults - int port = 8080; - String host = "127.0.0.1"; - File wwwroot = new File(".").getAbsoluteFile(); - - // Show licence if requested - for (int i = 0; i < args.length; ++i) - if (args[i].equalsIgnoreCase("-h")) - host = args[i + 1]; - else if (args[i].equalsIgnoreCase("-p")) - port = Integer.parseInt(args[i + 1]); - else if (args[i].equalsIgnoreCase("-d")) - wwwroot = new File(args[i + 1]).getAbsoluteFile(); - else if (args[i].toLowerCase().endsWith("licence")) { - System.out.println(LICENCE + "\n"); - break; - } - - ServerRunner.executeInstance(new SimpleWebServer(host, port, wwwroot)); - } -} -- cgit v1.2.3