aboutsummaryrefslogtreecommitdiff
path: root/samples
diff options
context:
space:
mode:
authorPaul Hawke <paul.hawke@gmail.com>2013-05-05 16:27:19 -0500
committerPaul Hawke <paul.hawke@gmail.com>2013-05-05 16:27:19 -0500
commite55ac2d9e57bc5c671c7b33356e96961af916fe8 (patch)
tree9f5d69e8918278b61e7b6f9c7de091d3fe728054 /samples
parentea902c03fff78b94eb3deccaf84a50dade8099af (diff)
downloadnanohttpd-e55ac2d9e57bc5c671c7b33356e96961af916fe8.tar.gz
Extracted and promoted the NanoHttpd Webserver to a top-level project (instead of being a "sample").
Diffstat (limited to 'samples')
-rw-r--r--samples/pom.xml5
-rw-r--r--samples/src/main/java/fi/iki/elonen/ServerRunner.java32
-rw-r--r--samples/src/main/java/fi/iki/elonen/SimpleWebServer.java323
3 files changed, 5 insertions, 355 deletions
diff --git a/samples/pom.xml b/samples/pom.xml
index cd955bd..a41c37c 100644
--- a/samples/pom.xml
+++ b/samples/pom.xml
@@ -20,6 +20,11 @@
<artifactId>nanohttpd</artifactId>
<version>1.0.0</version>
</dependency>
+ <dependency>
+ <groupId>fi.iki.elonen</groupId>
+ <artifactId>nanohttpd-webserver</artifactId>
+ <version>1.0.0</version>
+ </dependency>
</dependencies>
<distributionManagement>
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<String, String> MIME_TYPES;
- static {
- Map<String, String> mime = new HashMap<String, String>();
- 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 <elonen@iki.fi>\n"
- + "and Copyright (C) 2010 by Konstantinos Togias <info@ktogias.gr>\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<String, String> 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, "<html><body>Redirected: <a href=\"" + uri + "\">" + uri
- + "</a></body></html>");
- 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 = "<html><body><h1>Directory " + uri + "</h1><br/>";
-
- if (uri.length() > 1) {
- String u = uri.substring(0, uri.length() - 1);
- int slash = u.lastIndexOf('/');
- if (slash >= 0 && slash < u.length())
- msg += "<b><a href=\"" + uri.substring(0, slash + 1) + "\">..</a></b><br/>";
- }
-
- 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 += "<b>";
- files[i] += "/";
- }
-
- msg += "<a href=\"" + encodeUri(uri + files[i]) + "\">" + files[i] + "</a>";
-
- // Show file size
- if (curFile.isFile()) {
- long len = curFile.length();
- msg += " &nbsp;<font size=2>(";
- 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 += ")</font>";
- }
- msg += "<br/>";
- if (dir)
- msg += "</b>";
- }
- }
- msg += "</body></html>";
- 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<String, String> header, Map<String, String> parms, Map<String, String> files) {
- System.out.println(method + " '" + uri + "' ");
-
- Iterator<String> 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));
- }
-}