Java tutorial
/* * Unless otherwise specified through the '@author' tag or comments at * the top of the file or on a specific portion of the code the following license applies: * * Copyright (c) 2014, DoubleDoorDevelopment * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * The header specified or the above copyright notice, this list of conditions * and the following disclaimer below must be displayed at the top of the source code * of any web page received while using any part of the service this software provides. * * The header to be displayed: * This page was generated by DoubleDoorDevelopment's D3Backend or a derivative thereof. * * Neither the name of the project nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package net.doubledoordev.backend.webserver_old; import org.apache.commons.io.FilenameUtils; import java.io.*; import java.net.URLEncoder; import java.util.*; public abstract class SimpleWebServer extends NanoHTTPD { /** * Common mime type for dynamic content: binary */ public static final String MIME_DEFAULT_BINARY = "application/octet-stream"; /** * Default Index file names. */ public static final List<String> INDEX_FILE_NAMES = new ArrayList<String>() { { add("index.html"); } }; /** * Hashtable mapping (String)FILENAME_EXTENSION -> (String)MIME_TYPE */ public static final Map<String, String> MIME_TYPES = new HashMap<String, String>() { { put("css", "text/css"); put("htm", "text/html"); put("html", "text/html"); put("xml", "text/xml"); put("java", "text/x-java-source, text/java"); put("md", "text/plain"); put("txt", "text/plain"); put("asc", "text/plain"); put("gif", "image/gif"); put("jpg", "image/jpeg"); put("jpeg", "image/jpeg"); put("png", "image/png"); put("mp3", "audio/mpeg"); put("m3u", "audio/mpeg-url"); put("mp4", "video/mp4"); put("ogv", "video/ogg"); put("flv", "video/x-flv"); put("mov", "video/quicktime"); put("swf", "application/x-shockwave-flash"); put("js", "application/javascript"); put("pdf", "application/pdf"); put("doc", "application/msword"); put("ogg", "application/x-ogg"); put("zip", "application/octet-stream"); put("exe", "application/octet-stream"); put("class", "application/octet-stream"); } }; private final String rootDir; public SimpleWebServer(String host, int port, String wwwroot) { super(host, port); if (!wwwroot.endsWith("/")) wwwroot += "/"; this.rootDir = wwwroot; this.init(); } public SimpleWebServer(int port, String wwwroot) { super(port); if (!wwwroot.endsWith("/")) wwwroot += "/"; this.rootDir = wwwroot; this.init(); } /** * Used to initialize and customize the server. */ public void init() { } /** * 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; } protected Response respond(String uri) { // 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("../")) { return getForbiddenResponse("Won't serve ../ for security reasons."); } if (!canServeUri(uri)) { return getNotFoundResponse(); } Response response = serveResourceFile(uri); return response != null ? response : getNotFoundResponse(); } protected Response getNotFoundResponse() { return createResponse(Response.Status.NOT_FOUND, MIME_PLAINTEXT, "Error 404, file not found."); } protected Response getForbiddenResponse(String s) { return createResponse(Response.Status.FORBIDDEN, MIME_PLAINTEXT, "FORBIDDEN: " + s); } private boolean canServeUri(String uri) { return this.getClass().getResource(rootDir + uri) != null; } /** * Serves file from homeDir and its' subdirectories (only). Uses only URI, ignores all headers and HTTP parameters. */ public Response serveResourceFile(String uri) { Response res; try { InputStream stream = getClass().getResourceAsStream(rootDir + uri); int fileLen = stream.available(); res = createResponse(Response.Status.OK, getMimeTypeForFile(uri), stream); res.addHeader("Content-Length", "" + fileLen); } catch (IOException ioe) { res = getForbiddenResponse("Reading file failed."); } return res; } public Response serveFile(File file) { Response res; try { InputStream stream = new FileInputStream(file); int fileLen = stream.available(); res = createResponse(Response.Status.OK, MIME_TYPES.get(FilenameUtils.getExtension(file.getName().toLowerCase())), stream); res.addHeader("Content-Length", "" + fileLen); } catch (IOException ioe) { res = getForbiddenResponse("Reading file failed."); } return res; } // Get MIME type from file name extension, if possible public String getMimeTypeForFile(String uri) { int dot = uri.lastIndexOf('.'); String mime = null; if (dot >= 0) { mime = MIME_TYPES.get(uri.substring(dot + 1).toLowerCase()); } return mime == null ? MIME_DEFAULT_BINARY : mime; } // Announce that the file server accepts partial content requests public Response createResponse(Response.Status status, String mimeType, InputStream message) { Response res = new Response(status, mimeType, message); res.addHeader("Accept-Ranges", "bytes"); return res; } // Announce that the file server accepts partial content requests public Response createResponse(Response.Status status, String mimeType, String message) { Response res = new Response(status, mimeType, message); res.addHeader("Accept-Ranges", "bytes"); return res; } }