[
  {
    "path": ".gitignore",
    "content": "out\nbuild\ntarget\n\n*.iml\n*.ipr\n*.iws\n*.class\n\n.idea\n.classpath\n.project\n.gradle\ngradle/\ngradlew\ngradlew.bat\n\n# Vim Backup/Swap Files\n*~\n.swp\n.*.swp\n\n/.settings/\n/LICENSE.txt\n"
  },
  {
    "path": ".travis.yml",
    "content": "language: java\njdk:\n- openjdk7\n\nbefore_install:\n  - cat ~/.m2/settings.xml\n  - rm  ~/.m2/settings.xml\n\ninstall:\n  - mvn install -DskipTests=true\n\nscript:\n    - mvn test; export MAVEN_RESULT=$?\n    - if [ \"$MAVEN_RESULT\" -ne 0 ]; then exit 1; fi\n    - if [ \"$TRAVIS_BRANCH\" = \"master\" -a \"$TRAVIS_PULL_REQUEST\" = \"false\" ]; then mvn clean deploy --quiet --settings settings.xml; fi\n\nafter_success:\n  - mvn clean test jacoco:report coveralls:report\n  \n \nnotifications:\n  email:\n    - richard.vannieuwenhoven@adesso.at\n    - elonen@iki.fi\n    - diogo.duarte@techie.com\n    \nenv:\n global:\n  - secure: \"OtD0z3y4/OjSzg8irVD8v/u0TElcw8AiCCXb7a0UQEnTpGxcf5DOdkvHv0hF4xjHKFtlMMHxevW+a4C4NuFR8it8ZJ/i2m24reB28JicDcRQY9nwV/BR/T08CRG9KDz5EuTHgfPJDF0y+5MiVNwJVhHFviBWKuXyIuYouJ5IHgc=\"\n  - secure: \"tgTVycNLwYDM3U0EVK1TkffylQHfZihvSDC9QoZEo+wz9aBBLoAtUJP7DWltRQFOkfTeGltGHEfGM2/qkIG6Wz+hNFG/fveHqyI01JWXc64d7yBm7agaCP5uTtt2wjaZ7ZK5Mps5QoufblYu+j9gb2v31t9IdsJ9PUs0+wgE/WU=\"\n  \n"
  },
  {
    "path": "LICENSE.md",
    "content": "Copyright (c) 2012-2013 by Paul S. Hawke, 2001,2005-2013 by Jarno Elonen, 2010 by Konstantinos Togias\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\n\n* 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.\n\n* Neither the name of the NanoHttpd organization nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.\n\nTHIS 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.\n"
  },
  {
    "path": "README.md",
    "content": "## NanoHTTPD – a tiny web server in Java\n\n*NanoHTTPD* is a light-weight HTTP server designed for embedding in other applications, released under a Modified BSD licence.\n\nIt is being developed at Github and uses Apache Maven for builds & unit testing:\n\n * Build status: [![Build Status](https://api.travis-ci.org/NanoHttpd/nanohttpd.png)](https://travis-ci.org/NanoHttpd/nanohttpd)\n * Coverage Status: [![Coverage Status](https://coveralls.io/repos/NanoHttpd/nanohttpd/badge.svg)](https://coveralls.io/r/NanoHttpd/nanohttpd)\n * Current central released version: [![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.nanohttpd/nanohttpd/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.nanohttpd/nanohttpd)\n\n## Quickstart\n\nWe'll create a custom HTTP server project using Maven for build/dep system. This tutorial assumes you are using a Unix variant and a shell. First, install Maven and Java SDK if not already installed. Then run:\n\n    mvn compile\n    mvn exec:java -pl webserver -Dexec.mainClass=\"org.nanohttpd.webserver.SimpleWebServer\"\n    \nYou should now have a HTTP file server running on <http://localhost:8080/>.\n\n### Custom web app\n\nLet's raise the bar and build a custom web application next:\n\n    mvn archetype:generate -DgroupId=com.example -DartifactId=myHellopApp -DinteractiveMode=false\n    cd myHellopApp\n    \nEdit `pom.xml`, and add this between \\<dependencies\\>:\n \n\t<dependency>\n\t\t<groupId>org.nanohttpd</groupId> <!-- <groupId>com.nanohttpd</groupId> for 2.1.0 and earlier -->\n\t\t<artifactId>nanohttpd</artifactId>\n\t\t<version>2.2.0</version>\n\t</dependency>\n\t\nEdit `src/main/java/com/example/App.java` and replace it with:\n```java\n    package com.example;\n    \n    import java.io.IOException;\n    import java.util.Map;\n    \n    import fi.iki.elonen.NanoHTTPD;\n    // NOTE: If you're using NanoHTTPD >= 3.0.0 the namespace is different,\n    //       instead of the above import use the following:\n\t// import org.nanohttpd.NanoHTTPD;\n    \n    public class App extends NanoHTTPD {\n    \n        public App() throws IOException {\n            super(8080);\n            start(NanoHTTPD.SOCKET_READ_TIMEOUT, false);\n            System.out.println(\"\\nRunning! Point your browsers to http://localhost:8080/ \\n\");\n        }\n    \n        public static void main(String[] args) {\n            try {\n                new App();\n            } catch (IOException ioe) {\n                System.err.println(\"Couldn't start server:\\n\" + ioe);\n            }\n        }\n    \n        @Override\n        public Response serve(IHTTPSession session) {\n            String msg = \"<html><body><h1>Hello server</h1>\\n\";\n            Map<String, String> parms = session.getParms();\n            if (parms.get(\"username\") == null) {\n                msg += \"<form action='?' method='get'>\\n  <p>Your name: <input type='text' name='username'></p>\\n\" + \"</form>\\n\";\n            } else {\n                msg += \"<p>Hello, \" + parms.get(\"username\") + \"!</p>\";\n            }\n            return newFixedLengthResponse(msg + \"</body></html>\\n\");\n        }\n    }\n```\n\nCompile and run the server:\n \n    mvn compile\n    mvn exec:java -Dexec.mainClass=\"com.example.App\"\n    \nIf it started ok, point your browser at <http://localhost:8080/> and enjoy a web server that asks your name and replies with a greeting. \n\n### Nanolets\n\nNanolets are like servlets only that they have a extremely low profile. They offer an easy to use system for a more complex server application.\nThis text has to be extended with an example, so for now take a look at the unit tests for the usage. <https://github.com/NanoHttpd/nanohttpd/blob/master/nanolets/src/test/java/org/nanohttpd/junit/router/AppNanolets.java>\n\n## Status\n\nWe are currently in the process of stabilizing NanoHTTPD from the many pull requests and feature requests that were integrated over the last few months. The next release will come soon, and there will not be any more \"intended\" major changes before the next release. If you want to use the bleeding edge version, you can clone it from Github, or get it from sonatype.org (see \"Maven dependencies / Living on the edge\" below).\n\n## Project structure\n\nNanoHTTPD project currently consist of four parts:\n\n * `/core` – Fully functional HTTP(s) server consisting of one (1) Java file, ready to be customized/inherited for your own project.\n\n * `/samples` – Simple examples on how to customize NanoHTTPD. See *HelloServer.java* for a killer app that greets you enthusiastically!\n\n * `/websocket` – Websocket implementation, also in a single Java file. Depends on core.\n\n * `/webserver` – Standalone file server. Run & enjoy. A popular use seems to be serving files out off an Android device.\n\n * `/nanolets` – Standalone nano app server, giving a servlet like system to the implementor.\n\n * `/fileupload` – integration of the apache common file upload library.\n\n## Features\n### Core\n* Only one Java file, providing HTTP 1.1 support.\n* No fixed config files, logging, authorization etc. (Implement by yourself if you need them. Errors are passed to java.util.logging, though.)\n* Support for HTTPS (SSL).\n* Basic support for cookies.\n* Supports parameter parsing of GET and POST methods.\n* Some built-in support for HEAD, POST and DELETE requests. You can easily implement/customize any HTTP method, though.\n* Supports file upload. Uses memory for small uploads, temp files for large ones.\n* Never caches anything.\n* Does not limit bandwidth, request time or simultaneous connections by default.\n* All header names are converted to lower case so they don't vary between browsers/clients.\n* Persistent connections (Connection \"keep-alive\") support allowing multiple requests to be served over a single socket connection.\n\n### Websocket\n* Tested on Firefox, Chrome and IE.\n\n### Webserver\n* Default code serves files and shows (prints on console) all HTTP parameters and headers.\n* Supports both dynamic content and file serving.\n* File server supports directory listing, `index.html` and `index.htm`.\n* File server supports partial content (streaming & continue download).\n* File server supports ETags.\n* File server does the 301 redirection trick for directories without `/`.\n* File server serves also very long files without memory overhead.\n* Contains a built-in list of most common MIME types.\n* Runtime extension support (extensions that serve particular MIME types) - example extension that serves Markdown formatted files. Simply including an extension JAR in the webserver classpath is enough for the extension to be loaded.\n* Simple [CORS](https://en.wikipedia.org/wiki/Cross-origin_resource_sharing) support via `--cors` parameter\n  * by default serves `Access-Control-Allow-Headers: origin,accept,content-type`\n  * possibility to set `Access-Control-Allow-Headers` by setting System property: `AccessControlAllowHeader`\n  * _example: _ `-DAccessControlAllowHeader=origin,accept,content-type,Authorization`\n  * possible values:\n      * `--cors`: activates CORS support, `Access-Control-Allow-Origin` will be set to `*`.\n      * `--cors=some_value`: `Access-Control-Allow-Origin` will be set to `some_value`. \n\n**_CORS argument examples_**\n\n\n* `--cors=http://appOne.company.com`\n* `--cors=\"http://appOne.company.com, http://appTwo.company.com\"`: note the double quotes so that the two URLs are considered part of a single argument.\n\n## Maven dependencies\n\nNanoHTTPD is a Maven based project and deployed to central. Most development environments have means to access the central repository. The coordinates to use in Maven are: \n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.nanohttpd</groupId> <!-- <groupId>com.nanohttpd</groupId> for 2.1.0 and earlier -->\n\t\t\t<artifactId>nanohttpd</artifactId>\n\t\t\t<version>CURRENT_VERSION</version>\n\t\t</dependency>\n\t</dependencies>\n\n(Replace `CURRENT_VERSION` with whatever is reported latest at <http://nanohttpd.org/>.)\n\nThe coordinates for your development environment should correspond to these. When looking for an older version take care because we switched groupId from *com.nanohttpd* to *org.nanohttpd* in mid 2015.\n\nNext it depends what you are using NanoHTTPD for, there are three main usages.\n\n## Gradle dependencies\n\nIn gradle you can use NanoHTTPD the same way because gradle accesses the same central repository:\n\n\tdependencies {\n\t\truntime(\n\t\t\t[group: 'org.nanohttpd', name: 'nanohttpd', version: 'CURRENT_VERSION'],\n\t\t)\n\t}\n\n(Replace `CURRENT_VERSION` with whatever is reported latest at <http://nanohttpd.org/>.)\n\nJust replace the name with the artifact id of the module you want to use and gradle will find it for you. \n\n### Develop your own specialized HTTP service\n\nFor a specialized HTTP (HTTPS) service you can use the module with artifactId *nanohttpd*.\n\n\t\t<dependency>\n\t\t\t<groupId>org.nanohttpd</groupId> <!-- <groupId>com.nanohttpd</groupId> for 2.1.0 and earlier -->\n\t\t\t<artifactId>nanohttpd</artifactId>\n\t\t\t<version>CURRENT_VERSION</version>\n\t\t</dependency>\n\t\t\nHere you write your own subclass of *org.nanohttpd.NanoHTTPD* to configure and to serve the requests.\n  \n### Develop a websocket based service    \n\nFor a specialized websocket service you can use the module with artifactId *nanohttpd-websocket*.\n\n\t\t<dependency>\n\t\t\t<groupId>org.nanohttpd</groupId> <!-- <groupId>com.nanohttpd</groupId> for 2.1.0 and earlier -->\n\t\t\t<artifactId>nanohttpd-websocket</artifactId>\n\t\t\t<version>CURRENT_VERSION</version>\n\t\t</dependency>\n\nHere you write your own subclass of *org.nanohttpd.NanoWebSocketServer* to configure and to serve the websocket requests. A small standard echo example is included as *org.nanohttpd.samples.echo.DebugWebSocketServer*. You can use it as a starting point to implement your own services.\n\n### Develop a custom HTTP file server    \n\nFor a more classic approach, perhaps to just create a HTTP server serving mostly service files from your disk, you can use the module with artifactId *nanohttpd-webserver*.\n\n\t\t<dependency>\n\t\t\t<groupId>org.nanohttpd</groupId>\n\t\t\t<artifactId>nanohttpd-webserver</artifactId>\n\t\t\t<version>CURRENT_VERSION</version>\n\t\t</dependency>\n\nThe included class *org.nanohttpd.SimpleWebServer* is intended to be used as a starting point for your own implementation but it also can be used as is. Starting the class as is will start a HTTP server on port 8080 and publishing the current directory.\n\n### Living on the edge\n\nThe latest Github master version can be fetched through sonatype.org:\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<artifactId>nanohttpd</artifactId>\n\t\t\t<groupId>org.nanohttpd</groupId>\n\t\t\t<version>XXXXX-SNAPSHOT</version>\n\t\t</dependency>\n\t</dependencies>\n\t...\n\t<repositories>\n\t\t<repository>\n\t\t\t<id>sonatype-snapshots</id>\n\t\t\t<url>https://oss.sonatype.org/content/repositories/snapshots</url>\n\t\t\t<snapshots>\n\t\t\t\t<enabled>true</enabled>\n\t\t\t</snapshots>\n\t\t</repository>\n\t</repositories>\n\n### generating an self signed SSL certificate\n\nJust a hint how to generate a certificate for localhost.\n\n\tkeytool -genkey -keyalg RSA -alias selfsigned -keystore keystore.jks -storepass password -validity 360 -keysize 2048 -ext SAN=DNS:localhost,IP:127.0.0.1  -validity 9999\n\nThis will generate a keystore file named 'keystore.jks' with a self signed certificate for a host named localhost with the IP address 127.0.0.1 . Now\nyou can use:\n\n\tserver.makeSecure(NanoHTTPD.makeSSLSocketFactory(\"/keystore.jks\", \"password\".toCharArray()), null);\n\nBefore you start the server to make NanoHTTPD serve HTTPS connections, when you make sure 'keystore.jks' is in your classpath.\n \n-----\n\n*Thank you to everyone who has reported bugs and suggested fixes.*\n"
  },
  {
    "path": "build.gradle",
    "content": "allprojects {\n\tapply plugin: 'java'\n\tapply plugin: 'idea'\n\t\n\tgroup = 'org.nanohttpd'\n\tversion = '2.3.2-SNAPSHOT'\n}\n\nsubprojects {\n\tapply plugin: 'java'\n\tsourceCompatibility = 1.7\n\ttargetCompatibility = 1.7\n\t\n\trepositories {\n\t\tjcenter()\n\t}\n\t\n\tdependencies {\n\t\ttestCompile group: 'junit', name: 'junit', version: '4.12'\n\t}\n}\n\ntask wrapper(type: Wrapper) {\n\tgradleVersion = \"4.4.1\"\n}\n"
  },
  {
    "path": "core/.gitignore",
    "content": "/.settings/\n/LICENSE.txt\n"
  },
  {
    "path": "core/build.gradle",
    "content": "description = 'NanoHttpd-Core'\n\ndependencies {\n\ttestCompile group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.2.5'\n\ttestCompile group: 'org.apache.httpcomponents', name: 'httpmime', version: '4.2.5'\n}\n\ntask wrapper(type: Wrapper) {\n\tgradleVersion = \"4.4.1\"\n}\n"
  },
  {
    "path": "core/pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<parent>\n\t\t<groupId>org.nanohttpd</groupId>\n\t\t<artifactId>nanohttpd-project</artifactId>\n\t\t<version>2.3.2-SNAPSHOT</version>\n\t</parent>\n\t<artifactId>nanohttpd</artifactId>\n\t<packaging>jar</packaging>\n\t<name>NanoHttpd-Core</name>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.apache.httpcomponents</groupId>\n\t\t\t<artifactId>httpclient</artifactId>\n\t\t\t<version>4.2.5</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.apache.httpcomponents</groupId>\n\t\t\t<artifactId>httpmime</artifactId>\n\t\t\t<version>4.2.5</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t</dependencies>\n\t<properties>\n\t\t<minimal.coverage>0.82</minimal.coverage>\n\t</properties>\n</project>\n"
  },
  {
    "path": "core/src/main/java/org/nanohttpd/protocols/http/ClientHandler.java",
    "content": "package org.nanohttpd.protocols.http;\n\n/*\n * #%L\n * NanoHttpd-Core\n * %%\n * Copyright (C) 2012 - 2016 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.net.Socket;\nimport java.net.SocketException;\nimport java.net.SocketTimeoutException;\nimport java.util.logging.Level;\n\nimport org.nanohttpd.protocols.http.tempfiles.ITempFileManager;\n\n/**\n * The runnable that will be used for every new client connection.\n */\npublic class ClientHandler implements Runnable {\n\n    private final NanoHTTPD httpd;\n\n    private final InputStream inputStream;\n\n    private final Socket acceptSocket;\n\n    public ClientHandler(NanoHTTPD httpd, InputStream inputStream, Socket acceptSocket) {\n        this.httpd = httpd;\n        this.inputStream = inputStream;\n        this.acceptSocket = acceptSocket;\n    }\n\n    public void close() {\n        NanoHTTPD.safeClose(this.inputStream);\n        NanoHTTPD.safeClose(this.acceptSocket);\n    }\n\n    @Override\n    public void run() {\n        OutputStream outputStream = null;\n        try {\n            outputStream = this.acceptSocket.getOutputStream();\n            ITempFileManager tempFileManager = httpd.getTempFileManagerFactory().create();\n            HTTPSession session = new HTTPSession(httpd, tempFileManager, this.inputStream, outputStream, this.acceptSocket.getInetAddress());\n            while (!this.acceptSocket.isClosed()) {\n                session.execute();\n            }\n        } catch (Exception e) {\n            // When the socket is closed by the client,\n            // we throw our own SocketException\n            // to break the \"keep alive\" loop above. If\n            // the exception was anything other\n            // than the expected SocketException OR a\n            // SocketTimeoutException, print the\n            // stacktrace\n            if (!(e instanceof SocketException && \"NanoHttpd Shutdown\".equals(e.getMessage())) && !(e instanceof SocketTimeoutException)) {\n                NanoHTTPD.LOG.log(Level.SEVERE, \"Communication with the client broken, or an bug in the handler code\", e);\n            }\n        } finally {\n            NanoHTTPD.safeClose(outputStream);\n            NanoHTTPD.safeClose(this.inputStream);\n            NanoHTTPD.safeClose(this.acceptSocket);\n            httpd.asyncRunner.closed(this);\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/main/java/org/nanohttpd/protocols/http/HTTPSession.java",
    "content": "package org.nanohttpd.protocols.http;\n\n/*\n * #%L\n * NanoHttpd-Core\n * %%\n * Copyright (C) 2012 - 2016 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport java.io.BufferedInputStream;\nimport java.io.BufferedReader;\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.DataOutput;\nimport java.io.DataOutputStream;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.io.OutputStream;\nimport java.io.RandomAccessFile;\nimport java.net.InetAddress;\nimport java.net.SocketException;\nimport java.net.SocketTimeoutException;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.nio.charset.Charset;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.StringTokenizer;\nimport java.util.logging.Level;\nimport java.util.regex.Matcher;\n\nimport javax.net.ssl.SSLException;\n\nimport org.nanohttpd.protocols.http.NanoHTTPD.ResponseException;\nimport org.nanohttpd.protocols.http.content.ContentType;\nimport org.nanohttpd.protocols.http.content.CookieHandler;\nimport org.nanohttpd.protocols.http.request.Method;\nimport org.nanohttpd.protocols.http.response.Response;\nimport org.nanohttpd.protocols.http.response.Status;\nimport org.nanohttpd.protocols.http.tempfiles.ITempFile;\nimport org.nanohttpd.protocols.http.tempfiles.ITempFileManager;\n\npublic class HTTPSession implements IHTTPSession {\n\n    public static final String POST_DATA = \"postData\";\n\n    private static final int REQUEST_BUFFER_LEN = 512;\n\n    private static final int MEMORY_STORE_LIMIT = 1024;\n\n    public static final int BUFSIZE = 8192;\n\n    public static final int MAX_HEADER_SIZE = 1024;\n\n    private final NanoHTTPD httpd;\n\n    private final ITempFileManager tempFileManager;\n\n    private final OutputStream outputStream;\n\n    private final BufferedInputStream inputStream;\n\n    private int splitbyte;\n\n    private int rlen;\n\n    private String uri;\n\n    private Method method;\n\n    private Map<String, List<String>> parms;\n\n    private Map<String, String> headers;\n\n    private CookieHandler cookies;\n\n    private String queryParameterString;\n\n    private String remoteIp;\n\n    private String protocolVersion;\n\n    public HTTPSession(NanoHTTPD httpd, ITempFileManager tempFileManager, InputStream inputStream, OutputStream outputStream) {\n        this.httpd = httpd;\n        this.tempFileManager = tempFileManager;\n        this.inputStream = new BufferedInputStream(inputStream, HTTPSession.BUFSIZE);\n        this.outputStream = outputStream;\n    }\n\n    public HTTPSession(NanoHTTPD httpd, ITempFileManager tempFileManager, InputStream inputStream, OutputStream outputStream, InetAddress inetAddress) {\n        this.httpd = httpd;\n        this.tempFileManager = tempFileManager;\n        this.inputStream = new BufferedInputStream(inputStream, HTTPSession.BUFSIZE);\n        this.outputStream = outputStream;\n        this.remoteIp = inetAddress.isLoopbackAddress() || inetAddress.isAnyLocalAddress() ? \"127.0.0.1\" : inetAddress.getHostAddress().toString();\n        this.headers = new HashMap<String, String>();\n    }\n\n    /**\n     * Decodes the sent headers and loads the data into Key/value pairs\n     */\n    private void decodeHeader(BufferedReader in, Map<String, String> pre, Map<String, List<String>> parms, Map<String, String> headers) throws ResponseException {\n        try {\n            // Read the request line\n            String inLine = in.readLine();\n            if (inLine == null) {\n                return;\n            }\n\n            StringTokenizer st = new StringTokenizer(inLine);\n            if (!st.hasMoreTokens()) {\n                throw new ResponseException(Status.BAD_REQUEST, \"BAD REQUEST: Syntax error. Usage: GET /example/file.html\");\n            }\n\n            pre.put(\"method\", st.nextToken());\n\n            if (!st.hasMoreTokens()) {\n                throw new ResponseException(Status.BAD_REQUEST, \"BAD REQUEST: Missing URI. Usage: GET /example/file.html\");\n            }\n\n            String uri = st.nextToken();\n\n            // Decode parameters from the URI\n            int qmi = uri.indexOf('?');\n            if (qmi >= 0) {\n                decodeParms(uri.substring(qmi + 1), parms);\n                uri = NanoHTTPD.decodePercent(uri.substring(0, qmi));\n            } else {\n                uri = NanoHTTPD.decodePercent(uri);\n            }\n\n            // If there's another token, its protocol version,\n            // followed by HTTP headers.\n            // NOTE: this now forces header names lower case since they are\n            // case insensitive and vary by client.\n            if (st.hasMoreTokens()) {\n                protocolVersion = st.nextToken();\n            } else {\n                protocolVersion = \"HTTP/1.1\";\n                NanoHTTPD.LOG.log(Level.FINE, \"no protocol version specified, strange. Assuming HTTP/1.1.\");\n            }\n            String line = in.readLine();\n            while (line != null && !line.trim().isEmpty()) {\n                int p = line.indexOf(':');\n                if (p >= 0) {\n                    headers.put(line.substring(0, p).trim().toLowerCase(Locale.US), line.substring(p + 1).trim());\n                }\n                line = in.readLine();\n            }\n\n            pre.put(\"uri\", uri);\n        } catch (IOException ioe) {\n            throw new ResponseException(Status.INTERNAL_ERROR, \"SERVER INTERNAL ERROR: IOException: \" + ioe.getMessage(), ioe);\n        }\n    }\n\n    /**\n     * Decodes the Multipart Body data and put it into Key/Value pairs.\n     */\n    private void decodeMultipartFormData(ContentType contentType, ByteBuffer fbuf, Map<String, List<String>> parms, Map<String, String> files) throws ResponseException {\n        int pcount = 0;\n        try {\n            int[] boundaryIdxs = getBoundaryPositions(fbuf, contentType.getBoundary().getBytes());\n            if (boundaryIdxs.length < 2) {\n                throw new ResponseException(Status.BAD_REQUEST, \"BAD REQUEST: Content type is multipart/form-data but contains less than two boundary strings.\");\n            }\n\n            byte[] partHeaderBuff = new byte[MAX_HEADER_SIZE];\n            for (int boundaryIdx = 0; boundaryIdx < boundaryIdxs.length - 1; boundaryIdx++) {\n                fbuf.position(boundaryIdxs[boundaryIdx]);\n                int len = (fbuf.remaining() < MAX_HEADER_SIZE) ? fbuf.remaining() : MAX_HEADER_SIZE;\n                fbuf.get(partHeaderBuff, 0, len);\n                BufferedReader in =\n                        new BufferedReader(new InputStreamReader(new ByteArrayInputStream(partHeaderBuff, 0, len), Charset.forName(contentType.getEncoding())), len);\n\n                int headerLines = 0;\n                // First line is boundary string\n                String mpline = in.readLine();\n                headerLines++;\n                if (mpline == null || !mpline.contains(contentType.getBoundary())) {\n                    throw new ResponseException(Status.BAD_REQUEST, \"BAD REQUEST: Content type is multipart/form-data but chunk does not start with boundary.\");\n                }\n\n                String partName = null, fileName = null, partContentType = null;\n                // Parse the reset of the header lines\n                mpline = in.readLine();\n                headerLines++;\n                while (mpline != null && mpline.trim().length() > 0) {\n                    Matcher matcher = NanoHTTPD.CONTENT_DISPOSITION_PATTERN.matcher(mpline);\n                    if (matcher.matches()) {\n                        String attributeString = matcher.group(2);\n                        matcher = NanoHTTPD.CONTENT_DISPOSITION_ATTRIBUTE_PATTERN.matcher(attributeString);\n                        while (matcher.find()) {\n                            String key = matcher.group(1);\n                            if (\"name\".equalsIgnoreCase(key)) {\n                                partName = matcher.group(2);\n                            } else if (\"filename\".equalsIgnoreCase(key)) {\n                                fileName = matcher.group(2);\n                                // add these two line to support multiple\n                                // files uploaded using the same field Id\n                                if (!fileName.isEmpty()) {\n                                    if (pcount > 0)\n                                        partName = partName + String.valueOf(pcount++);\n                                    else\n                                        pcount++;\n                                }\n                            }\n                        }\n                    }\n                    matcher = NanoHTTPD.CONTENT_TYPE_PATTERN.matcher(mpline);\n                    if (matcher.matches()) {\n                        partContentType = matcher.group(2).trim();\n                    }\n                    mpline = in.readLine();\n                    headerLines++;\n                }\n                int partHeaderLength = 0;\n                while (headerLines-- > 0) {\n                    partHeaderLength = scipOverNewLine(partHeaderBuff, partHeaderLength);\n                }\n                // Read the part data\n                if (partHeaderLength >= len - 4) {\n                    throw new ResponseException(Status.INTERNAL_ERROR, \"Multipart header size exceeds MAX_HEADER_SIZE.\");\n                }\n                int partDataStart = boundaryIdxs[boundaryIdx] + partHeaderLength;\n                int partDataEnd = boundaryIdxs[boundaryIdx + 1] - 4;\n\n                fbuf.position(partDataStart);\n\n                List<String> values = parms.get(partName);\n                if (values == null) {\n                    values = new ArrayList<String>();\n                    parms.put(partName, values);\n                }\n\n                if (partContentType == null) {\n                    // Read the part into a string\n                    byte[] data_bytes = new byte[partDataEnd - partDataStart];\n                    fbuf.get(data_bytes);\n\n                    values.add(new String(data_bytes, contentType.getEncoding()));\n                } else {\n                    // Read it into a file\n                    String path = saveTmpFile(fbuf, partDataStart, partDataEnd - partDataStart, fileName);\n                    if (!files.containsKey(partName)) {\n                        files.put(partName, path);\n                    } else {\n                        int count = 2;\n                        while (files.containsKey(partName + count)) {\n                            count++;\n                        }\n                        files.put(partName + count, path);\n                    }\n                    values.add(fileName);\n                }\n            }\n        } catch (ResponseException re) {\n            throw re;\n        } catch (Exception e) {\n            throw new ResponseException(Status.INTERNAL_ERROR, e.toString());\n        }\n    }\n\n    private int scipOverNewLine(byte[] partHeaderBuff, int index) {\n        while (partHeaderBuff[index] != '\\n') {\n            index++;\n        }\n        return ++index;\n    }\n\n    /**\n     * Decodes parameters in percent-encoded URI-format ( e.g.\n     * \"name=Jack%20Daniels&pass=Single%20Malt\" ) and adds them to given Map.\n     */\n    private void decodeParms(String parms, Map<String, List<String>> p) {\n        if (parms == null) {\n            this.queryParameterString = \"\";\n            return;\n        }\n\n        this.queryParameterString = parms;\n        StringTokenizer st = new StringTokenizer(parms, \"&\");\n        while (st.hasMoreTokens()) {\n            String e = st.nextToken();\n            int sep = e.indexOf('=');\n            String key = null;\n            String value = null;\n\n            if (sep >= 0) {\n                key = NanoHTTPD.decodePercent(e.substring(0, sep)).trim();\n                value = NanoHTTPD.decodePercent(e.substring(sep + 1));\n            } else {\n                key = NanoHTTPD.decodePercent(e).trim();\n                value = \"\";\n            }\n\n            List<String> values = p.get(key);\n            if (values == null) {\n                values = new ArrayList<String>();\n                p.put(key, values);\n            }\n\n            values.add(value);\n        }\n    }\n\n    @Override\n    public void execute() throws IOException {\n        Response r = null;\n        try {\n            // Read the first 8192 bytes.\n            // The full header should fit in here.\n            // Apache's default header limit is 8KB.\n            // Do NOT assume that a single read will get the entire header\n            // at once!\n            byte[] buf = new byte[HTTPSession.BUFSIZE];\n            this.splitbyte = 0;\n            this.rlen = 0;\n\n            int read = -1;\n            this.inputStream.mark(HTTPSession.BUFSIZE);\n            try {\n                read = this.inputStream.read(buf, 0, HTTPSession.BUFSIZE);\n            } catch (SSLException e) {\n                throw e;\n            } catch (IOException e) {\n                NanoHTTPD.safeClose(this.inputStream);\n                NanoHTTPD.safeClose(this.outputStream);\n                throw new SocketException(\"NanoHttpd Shutdown\");\n            }\n            if (read == -1) {\n                // socket was been closed\n                NanoHTTPD.safeClose(this.inputStream);\n                NanoHTTPD.safeClose(this.outputStream);\n                throw new SocketException(\"NanoHttpd Shutdown\");\n            }\n            while (read > 0) {\n                this.rlen += read;\n                this.splitbyte = findHeaderEnd(buf, this.rlen);\n                if (this.splitbyte > 0) {\n                    break;\n                }\n                read = this.inputStream.read(buf, this.rlen, HTTPSession.BUFSIZE - this.rlen);\n            }\n\n            if (this.splitbyte < this.rlen) {\n                this.inputStream.reset();\n                this.inputStream.skip(this.splitbyte);\n            }\n\n            this.parms = new HashMap<String, List<String>>();\n            if (null == this.headers) {\n                this.headers = new HashMap<String, String>();\n            } else {\n                this.headers.clear();\n            }\n\n            // Create a BufferedReader for parsing the header.\n            BufferedReader hin = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(buf, 0, this.rlen)));\n\n            // Decode the header into parms and header java properties\n            Map<String, String> pre = new HashMap<String, String>();\n            decodeHeader(hin, pre, this.parms, this.headers);\n\n            if (null != this.remoteIp) {\n                this.headers.put(\"remote-addr\", this.remoteIp);\n                this.headers.put(\"http-client-ip\", this.remoteIp);\n            }\n\n            this.method = Method.lookup(pre.get(\"method\"));\n            if (this.method == null) {\n                throw new ResponseException(Status.BAD_REQUEST, \"BAD REQUEST: Syntax error. HTTP verb \" + pre.get(\"method\") + \" unhandled.\");\n            }\n\n            this.uri = pre.get(\"uri\");\n\n            this.cookies = new CookieHandler(this.headers);\n\n            String connection = this.headers.get(\"connection\");\n            boolean keepAlive = \"HTTP/1.1\".equals(protocolVersion) && (connection == null || !connection.matches(\"(?i).*close.*\"));\n\n            // Ok, now do the serve()\n\n            // TODO: long body_size = getBodySize();\n            // TODO: long pos_before_serve = this.inputStream.totalRead()\n            // (requires implementation for totalRead())\n            r = httpd.handle(this);\n            // TODO: this.inputStream.skip(body_size -\n            // (this.inputStream.totalRead() - pos_before_serve))\n\n            if (r == null) {\n                throw new ResponseException(Status.INTERNAL_ERROR, \"SERVER INTERNAL ERROR: Serve() returned a null response.\");\n            } else {\n                String acceptEncoding = this.headers.get(\"accept-encoding\");\n                this.cookies.unloadQueue(r);\n                r.setRequestMethod(this.method);\n                if (acceptEncoding == null || !acceptEncoding.contains(\"gzip\")) {\n                    r.setUseGzip(false);\n                }\n                r.setKeepAlive(keepAlive);\n                r.send(this.outputStream);\n            }\n            if (!keepAlive || r.isCloseConnection()) {\n                throw new SocketException(\"NanoHttpd Shutdown\");\n            }\n        } catch (SocketException e) {\n            // throw it out to close socket object (finalAccept)\n            throw e;\n        } catch (SocketTimeoutException ste) {\n            // treat socket timeouts the same way we treat socket exceptions\n            // i.e. close the stream & finalAccept object by throwing the\n            // exception up the call stack.\n            throw ste;\n        } catch (SSLException ssle) {\n            Response resp = Response.newFixedLengthResponse(Status.INTERNAL_ERROR, NanoHTTPD.MIME_PLAINTEXT, \"SSL PROTOCOL FAILURE: \" + ssle.getMessage());\n            resp.send(this.outputStream);\n            NanoHTTPD.safeClose(this.outputStream);\n        } catch (IOException ioe) {\n            Response resp = Response.newFixedLengthResponse(Status.INTERNAL_ERROR, NanoHTTPD.MIME_PLAINTEXT, \"SERVER INTERNAL ERROR: IOException: \" + ioe.getMessage());\n            resp.send(this.outputStream);\n            NanoHTTPD.safeClose(this.outputStream);\n        } catch (ResponseException re) {\n            Response resp = Response.newFixedLengthResponse(re.getStatus(), NanoHTTPD.MIME_PLAINTEXT, re.getMessage());\n            resp.send(this.outputStream);\n            NanoHTTPD.safeClose(this.outputStream);\n        } finally {\n            NanoHTTPD.safeClose(r);\n            this.tempFileManager.clear();\n        }\n    }\n\n    /**\n     * Find byte index separating header from body. It must be the last byte of\n     * the first two sequential new lines.\n     */\n    private int findHeaderEnd(final byte[] buf, int rlen) {\n        int splitbyte = 0;\n        while (splitbyte + 1 < rlen) {\n\n            // RFC2616\n            if (buf[splitbyte] == '\\r' && buf[splitbyte + 1] == '\\n' && splitbyte + 3 < rlen && buf[splitbyte + 2] == '\\r' && buf[splitbyte + 3] == '\\n') {\n                return splitbyte + 4;\n            }\n\n            // tolerance\n            if (buf[splitbyte] == '\\n' && buf[splitbyte + 1] == '\\n') {\n                return splitbyte + 2;\n            }\n            splitbyte++;\n        }\n        return 0;\n    }\n\n    /**\n     * Find the byte positions where multipart boundaries start. This reads a\n     * large block at a time and uses a temporary buffer to optimize (memory\n     * mapped) file access.\n     */\n    private int[] getBoundaryPositions(ByteBuffer b, byte[] boundary) {\n        int[] res = new int[0];\n        if (b.remaining() < boundary.length) {\n            return res;\n        }\n\n        int search_window_pos = 0;\n        byte[] search_window = new byte[4 * 1024 + boundary.length];\n\n        int first_fill = (b.remaining() < search_window.length) ? b.remaining() : search_window.length;\n        b.get(search_window, 0, first_fill);\n        int new_bytes = first_fill - boundary.length;\n\n        do {\n            // Search the search_window\n            for (int j = 0; j < new_bytes; j++) {\n                for (int i = 0; i < boundary.length; i++) {\n                    if (search_window[j + i] != boundary[i])\n                        break;\n                    if (i == boundary.length - 1) {\n                        // Match found, add it to results\n                        int[] new_res = new int[res.length + 1];\n                        System.arraycopy(res, 0, new_res, 0, res.length);\n                        new_res[res.length] = search_window_pos + j;\n                        res = new_res;\n                    }\n                }\n            }\n            search_window_pos += new_bytes;\n\n            // Copy the end of the buffer to the start\n            System.arraycopy(search_window, search_window.length - boundary.length, search_window, 0, boundary.length);\n\n            // Refill search_window\n            new_bytes = search_window.length - boundary.length;\n            new_bytes = (b.remaining() < new_bytes) ? b.remaining() : new_bytes;\n            b.get(search_window, boundary.length, new_bytes);\n        } while (new_bytes > 0);\n        return res;\n    }\n\n    @Override\n    public CookieHandler getCookies() {\n        return this.cookies;\n    }\n\n    @Override\n    public final Map<String, String> getHeaders() {\n        return this.headers;\n    }\n\n    @Override\n    public final InputStream getInputStream() {\n        return this.inputStream;\n    }\n\n    @Override\n    public final Method getMethod() {\n        return this.method;\n    }\n\n    /**\n     * @deprecated use {@link #getParameters()} instead.\n     */\n    @Override\n    @Deprecated\n    public final Map<String, String> getParms() {\n        Map<String, String> result = new HashMap<String, String>();\n        for (String key : this.parms.keySet()) {\n            result.put(key, this.parms.get(key).get(0));\n        }\n\n        return result;\n    }\n\n    @Override\n    public final Map<String, List<String>> getParameters() {\n        return this.parms;\n    }\n\n    @Override\n    public String getQueryParameterString() {\n        return this.queryParameterString;\n    }\n\n    private RandomAccessFile getTmpBucket() {\n        try {\n            ITempFile tempFile = this.tempFileManager.createTempFile(null);\n            return new RandomAccessFile(tempFile.getName(), \"rw\");\n        } catch (Exception e) {\n            throw new Error(e); // we won't recover, so throw an error\n        }\n    }\n\n    @Override\n    public final String getUri() {\n        return this.uri;\n    }\n\n    /**\n     * Deduce body length in bytes. Either from \"content-length\" header or read\n     * bytes.\n     */\n    public long getBodySize() {\n        if (this.headers.containsKey(\"content-length\")) {\n            return Long.parseLong(this.headers.get(\"content-length\"));\n        } else if (this.splitbyte < this.rlen) {\n            return this.rlen - this.splitbyte;\n        }\n        return 0;\n    }\n\n    @Override\n    public void parseBody(Map<String, String> files) throws IOException, ResponseException {\n        RandomAccessFile randomAccessFile = null;\n        try {\n            long size = getBodySize();\n            ByteArrayOutputStream baos = null;\n            DataOutput requestDataOutput = null;\n\n            // Store the request in memory or a file, depending on size\n            if (size < MEMORY_STORE_LIMIT) {\n                baos = new ByteArrayOutputStream();\n                requestDataOutput = new DataOutputStream(baos);\n            } else {\n                randomAccessFile = getTmpBucket();\n                requestDataOutput = randomAccessFile;\n            }\n\n            // Read all the body and write it to request_data_output\n            byte[] buf = new byte[REQUEST_BUFFER_LEN];\n            while (this.rlen >= 0 && size > 0) {\n                this.rlen = this.inputStream.read(buf, 0, (int) Math.min(size, REQUEST_BUFFER_LEN));\n                size -= this.rlen;\n                if (this.rlen > 0) {\n                    requestDataOutput.write(buf, 0, this.rlen);\n                }\n            }\n\n            ByteBuffer fbuf = null;\n            if (baos != null) {\n                fbuf = ByteBuffer.wrap(baos.toByteArray(), 0, baos.size());\n            } else {\n                fbuf = randomAccessFile.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, randomAccessFile.length());\n                randomAccessFile.seek(0);\n            }\n\n            // If the method is POST, there may be parameters\n            // in data section, too, read it:\n            if (Method.POST.equals(this.method)) {\n                ContentType contentType = new ContentType(this.headers.get(\"content-type\"));\n                if (contentType.isMultipart()) {\n                    String boundary = contentType.getBoundary();\n                    if (boundary == null) {\n                        throw new ResponseException(Status.BAD_REQUEST, \"BAD REQUEST: Content type is multipart/form-data but boundary missing. Usage: GET /example/file.html\");\n                    }\n                    decodeMultipartFormData(contentType, fbuf, this.parms, files);\n                } else {\n                    byte[] postBytes = new byte[fbuf.remaining()];\n                    fbuf.get(postBytes);\n                    String postLine = new String(postBytes, contentType.getEncoding()).trim();\n                    // Handle application/x-www-form-urlencoded\n                    if (\"application/x-www-form-urlencoded\".equalsIgnoreCase(contentType.getContentType())) {\n                        decodeParms(postLine, this.parms);\n                    } else if (postLine.length() != 0) {\n                        // Special case for raw POST data => create a\n                        // special files entry \"postData\" with raw content\n                        // data\n                        files.put(POST_DATA, postLine);\n                    }\n                }\n            } else if (Method.PUT.equals(this.method)) {\n                files.put(\"content\", saveTmpFile(fbuf, 0, fbuf.limit(), null));\n            }\n        } finally {\n            NanoHTTPD.safeClose(randomAccessFile);\n        }\n    }\n\n    /**\n     * Retrieves the content of a sent file and saves it to a temporary file.\n     * The full path to the saved file is returned.\n     */\n    private String saveTmpFile(ByteBuffer b, int offset, int len, String filename_hint) {\n        String path = \"\";\n        if (len > 0) {\n            FileOutputStream fileOutputStream = null;\n            try {\n                ITempFile tempFile = this.tempFileManager.createTempFile(filename_hint);\n                ByteBuffer src = b.duplicate();\n                fileOutputStream = new FileOutputStream(tempFile.getName());\n                FileChannel dest = fileOutputStream.getChannel();\n                src.position(offset).limit(offset + len);\n                dest.write(src.slice());\n                path = tempFile.getName();\n            } catch (Exception e) { // Catch exception if any\n                throw new Error(e); // we won't recover, so throw an error\n            } finally {\n                NanoHTTPD.safeClose(fileOutputStream);\n            }\n        }\n        return path;\n    }\n\n    @Override\n    public String getRemoteIpAddress() {\n        return this.remoteIp;\n    }\n}\n"
  },
  {
    "path": "core/src/main/java/org/nanohttpd/protocols/http/IHTTPSession.java",
    "content": "package org.nanohttpd.protocols.http;\n\n/*\n * #%L\n * NanoHttpd-Core\n * %%\n * Copyright (C) 2012 - 2016 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.nanohttpd.protocols.http.NanoHTTPD.ResponseException;\nimport org.nanohttpd.protocols.http.content.CookieHandler;\nimport org.nanohttpd.protocols.http.request.Method;\n\n/**\n * Handles one session, i.e. parses the HTTP request and returns the response.\n */\npublic interface IHTTPSession {\n\n    void execute() throws IOException;\n\n    CookieHandler getCookies();\n\n    Map<String, String> getHeaders();\n\n    InputStream getInputStream();\n\n    Method getMethod();\n\n    /**\n     * This method will only return the first value for a given parameter. You\n     * will want to use getParameters if you expect multiple values for a given\n     * key.\n     * \n     * @deprecated use {@link #getParameters()} instead.\n     */\n    @Deprecated\n    Map<String, String> getParms();\n\n    Map<String, List<String>> getParameters();\n\n    String getQueryParameterString();\n\n    /**\n     * @return the path part of the URL.\n     */\n    String getUri();\n\n    /**\n     * Adds the files in the request body to the files map.\n     * \n     * @param files\n     *            map to modify\n     */\n    void parseBody(Map<String, String> files) throws IOException, ResponseException;\n\n    /**\n     * Get the remote ip address of the requester.\n     * \n     * @return the IP address.\n     */\n    String getRemoteIpAddress();\n}\n"
  },
  {
    "path": "core/src/main/java/org/nanohttpd/protocols/http/NanoHTTPD.java",
    "content": "package org.nanohttpd.protocols.http;\n\n/*\n * #%L\n * NanoHttpd-Core\n * %%\n * Copyright (C) 2012 - 2016 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport java.io.Closeable;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.UnsupportedEncodingException;\nimport java.net.ServerSocket;\nimport java.net.Socket;\nimport java.net.URL;\nimport java.net.URLDecoder;\nimport java.security.KeyStore;\nimport java.util.ArrayList;\nimport java.util.Enumeration;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Properties;\nimport java.util.StringTokenizer;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\nimport java.util.regex.Pattern;\n\nimport javax.net.ssl.KeyManager;\nimport javax.net.ssl.KeyManagerFactory;\nimport javax.net.ssl.SSLContext;\nimport javax.net.ssl.SSLServerSocketFactory;\nimport javax.net.ssl.TrustManagerFactory;\n\nimport org.nanohttpd.protocols.http.response.Response;\nimport org.nanohttpd.protocols.http.response.Status;\nimport org.nanohttpd.protocols.http.sockets.DefaultServerSocketFactory;\nimport org.nanohttpd.protocols.http.sockets.SecureServerSocketFactory;\nimport org.nanohttpd.protocols.http.tempfiles.DefaultTempFileManagerFactory;\nimport org.nanohttpd.protocols.http.tempfiles.ITempFileManager;\nimport org.nanohttpd.protocols.http.threading.DefaultAsyncRunner;\nimport org.nanohttpd.protocols.http.threading.IAsyncRunner;\nimport org.nanohttpd.util.IFactory;\nimport org.nanohttpd.util.IFactoryThrowing;\nimport org.nanohttpd.util.IHandler;\n\n/**\n * A simple, tiny, nicely embeddable HTTP server in Java\n * <p/>\n * <p/>\n * NanoHTTPD\n * <p>\n * Copyright (c) 2012-2013 by Paul S. Hawke, 2001,2005-2013 by Jarno Elonen,\n * 2010 by Konstantinos Togias\n * </p>\n * <p/>\n * <p/>\n * <b>Features + limitations: </b>\n * <ul>\n * <p/>\n * <li>Only one Java file</li>\n * <li>Java 5 compatible</li>\n * <li>Released as open source, Modified BSD licence</li>\n * <li>No fixed config files, logging, authorization etc. (Implement yourself if\n * you need them.)</li>\n * <li>Supports parameter parsing of GET and POST methods (+ rudimentary PUT\n * support in 1.25)</li>\n * <li>Supports both dynamic content and file serving</li>\n * <li>Supports file upload (since version 1.2, 2010)</li>\n * <li>Supports partial content (streaming)</li>\n * <li>Supports ETags</li>\n * <li>Never caches anything</li>\n * <li>Doesn't limit bandwidth, request time or simultaneous connections</li>\n * <li>Default code serves files and shows all HTTP parameters and headers</li>\n * <li>File server supports directory listing, index.html and index.htm</li>\n * <li>File server supports partial content (streaming)</li>\n * <li>File server supports ETags</li>\n * <li>File server does the 301 redirection trick for directories without '/'</li>\n * <li>File server supports simple skipping for files (continue download)</li>\n * <li>File server serves also very long files without memory overhead</li>\n * <li>Contains a built-in list of most common MIME types</li>\n * <li>All header names are converted to lower case so they don't vary between\n * browsers/clients</li>\n * <p/>\n * </ul>\n * <p/>\n * <p/>\n * <b>How to use: </b>\n * <ul>\n * <p/>\n * <li>Subclass and implement serve() and embed to your own program</li>\n * <p/>\n * </ul>\n * <p/>\n * See the separate \"LICENSE.md\" file for the distribution license (Modified BSD\n * licence)\n */\npublic abstract class NanoHTTPD {\n\n    public static final String CONTENT_DISPOSITION_REGEX = \"([ |\\t]*Content-Disposition[ |\\t]*:)(.*)\";\n\n    public static final Pattern CONTENT_DISPOSITION_PATTERN = Pattern.compile(CONTENT_DISPOSITION_REGEX, Pattern.CASE_INSENSITIVE);\n\n    public static final String CONTENT_TYPE_REGEX = \"([ |\\t]*content-type[ |\\t]*:)(.*)\";\n\n    public static final Pattern CONTENT_TYPE_PATTERN = Pattern.compile(CONTENT_TYPE_REGEX, Pattern.CASE_INSENSITIVE);\n\n    public static final String CONTENT_DISPOSITION_ATTRIBUTE_REGEX = \"[ |\\t]*([a-zA-Z]*)[ |\\t]*=[ |\\t]*['|\\\"]([^\\\"^']*)['|\\\"]\";\n\n    public static final Pattern CONTENT_DISPOSITION_ATTRIBUTE_PATTERN = Pattern.compile(CONTENT_DISPOSITION_ATTRIBUTE_REGEX);\n\n    public static final class ResponseException extends Exception {\n\n        private static final long serialVersionUID = 6569838532917408380L;\n\n        private final Status status;\n\n        public ResponseException(Status status, String message) {\n            super(message);\n            this.status = status;\n        }\n\n        public ResponseException(Status status, String message, Exception e) {\n            super(message, e);\n            this.status = status;\n        }\n\n        public Status getStatus() {\n            return this.status;\n        }\n    }\n\n    /**\n     * Maximum time to wait on Socket.getInputStream().read() (in milliseconds)\n     * This is required as the Keep-Alive HTTP connections would otherwise block\n     * the socket reading thread forever (or as long the browser is open).\n     */\n    public static final int SOCKET_READ_TIMEOUT = 5000;\n\n    /**\n     * Common MIME type for dynamic content: plain text\n     */\n    public static final String MIME_PLAINTEXT = \"text/plain\";\n\n    /**\n     * Common MIME type for dynamic content: html\n     */\n    public static final String MIME_HTML = \"text/html\";\n\n    /**\n     * Pseudo-Parameter to use to store the actual query string in the\n     * parameters map for later re-processing.\n     */\n    private static final String QUERY_STRING_PARAMETER = \"NanoHttpd.QUERY_STRING\";\n\n    /**\n     * logger to log to.\n     */\n    public static final Logger LOG = Logger.getLogger(NanoHTTPD.class.getName());\n\n    /**\n     * Hashtable mapping (String)FILENAME_EXTENSION -> (String)MIME_TYPE\n     */\n    protected static Map<String, String> MIME_TYPES;\n\n    public static Map<String, String> mimeTypes() {\n        if (MIME_TYPES == null) {\n            MIME_TYPES = new HashMap<String, String>();\n            loadMimeTypes(MIME_TYPES, \"META-INF/nanohttpd/default-mimetypes.properties\");\n            loadMimeTypes(MIME_TYPES, \"META-INF/nanohttpd/mimetypes.properties\");\n            if (MIME_TYPES.isEmpty()) {\n                LOG.log(Level.WARNING, \"no mime types found in the classpath! please provide mimetypes.properties\");\n            }\n        }\n        return MIME_TYPES;\n    }\n\n    @SuppressWarnings({\n        \"unchecked\",\n        \"rawtypes\"\n    })\n    private static void loadMimeTypes(Map<String, String> result, String resourceName) {\n        try {\n            Enumeration<URL> resources = NanoHTTPD.class.getClassLoader().getResources(resourceName);\n            while (resources.hasMoreElements()) {\n                URL url = (URL) resources.nextElement();\n                Properties properties = new Properties();\n                InputStream stream = null;\n                try {\n                    stream = url.openStream();\n                    properties.load(stream);\n                } catch (IOException e) {\n                    LOG.log(Level.SEVERE, \"could not load mimetypes from \" + url, e);\n                } finally {\n                    safeClose(stream);\n                }\n                result.putAll((Map) properties);\n            }\n        } catch (IOException e) {\n            LOG.log(Level.INFO, \"no mime types available at \" + resourceName);\n        }\n    };\n\n    /**\n     * Creates an SSLSocketFactory for HTTPS. Pass a loaded KeyStore and an\n     * array of loaded KeyManagers. These objects must properly\n     * loaded/initialized by the caller.\n     */\n    public static SSLServerSocketFactory makeSSLSocketFactory(KeyStore loadedKeyStore, KeyManager[] keyManagers) throws IOException {\n        SSLServerSocketFactory res = null;\n        try {\n            TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());\n            trustManagerFactory.init(loadedKeyStore);\n            SSLContext ctx = SSLContext.getInstance(\"TLS\");\n            ctx.init(keyManagers, trustManagerFactory.getTrustManagers(), null);\n            res = ctx.getServerSocketFactory();\n        } catch (Exception e) {\n            throw new IOException(e.getMessage());\n        }\n        return res;\n    }\n\n    /**\n     * Creates an SSLSocketFactory for HTTPS. Pass a loaded KeyStore and a\n     * loaded KeyManagerFactory. These objects must properly loaded/initialized\n     * by the caller.\n     */\n    public static SSLServerSocketFactory makeSSLSocketFactory(KeyStore loadedKeyStore, KeyManagerFactory loadedKeyFactory) throws IOException {\n        try {\n            return makeSSLSocketFactory(loadedKeyStore, loadedKeyFactory.getKeyManagers());\n        } catch (Exception e) {\n            throw new IOException(e.getMessage());\n        }\n    }\n\n    /**\n     * Creates an SSLSocketFactory for HTTPS. Pass a KeyStore resource with your\n     * certificate and passphrase\n     */\n    public static SSLServerSocketFactory makeSSLSocketFactory(String keyAndTrustStoreClasspathPath, char[] passphrase) throws IOException {\n        try {\n            KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());\n            InputStream keystoreStream = NanoHTTPD.class.getResourceAsStream(keyAndTrustStoreClasspathPath);\n\n            if (keystoreStream == null) {\n                throw new IOException(\"Unable to load keystore from classpath: \" + keyAndTrustStoreClasspathPath);\n            }\n\n            keystore.load(keystoreStream, passphrase);\n            KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());\n            keyManagerFactory.init(keystore, passphrase);\n            return makeSSLSocketFactory(keystore, keyManagerFactory);\n        } catch (Exception e) {\n            throw new IOException(e.getMessage());\n        }\n    }\n\n    /**\n     * Get MIME type from file name extension, if possible\n     * \n     * @param uri\n     *            the string representing a file\n     * @return the connected mime/type\n     */\n    public static String getMimeTypeForFile(String uri) {\n        int dot = uri.lastIndexOf('.');\n        String mime = null;\n        if (dot >= 0) {\n            mime = mimeTypes().get(uri.substring(dot + 1).toLowerCase());\n        }\n        return mime == null ? \"application/octet-stream\" : mime;\n    }\n\n    public static final void safeClose(Object closeable) {\n        try {\n            if (closeable != null) {\n                if (closeable instanceof Closeable) {\n                    ((Closeable) closeable).close();\n                } else if (closeable instanceof Socket) {\n                    ((Socket) closeable).close();\n                } else if (closeable instanceof ServerSocket) {\n                    ((ServerSocket) closeable).close();\n                } else {\n                    throw new IllegalArgumentException(\"Unknown object to close\");\n                }\n            }\n        } catch (IOException e) {\n            NanoHTTPD.LOG.log(Level.SEVERE, \"Could not close\", e);\n        }\n    }\n\n    public final String hostname;\n\n    public final int myPort;\n\n    private volatile ServerSocket myServerSocket;\n\n    public ServerSocket getMyServerSocket() {\n        return myServerSocket;\n    }\n\n    private IFactoryThrowing<ServerSocket, IOException> serverSocketFactory = new DefaultServerSocketFactory();\n\n    private Thread myThread;\n\n    private IHandler<IHTTPSession, Response> httpHandler;\n\n    protected List<IHandler<IHTTPSession, Response>> interceptors = new ArrayList<IHandler<IHTTPSession, Response>>(4);\n\n    /**\n     * Pluggable strategy for asynchronously executing requests.\n     */\n    protected IAsyncRunner asyncRunner;\n\n    /**\n     * Pluggable strategy for creating and cleaning up temporary files.\n     */\n    private IFactory<ITempFileManager> tempFileManagerFactory;\n\n    /**\n     * Constructs an HTTP server on given port.\n     */\n    public NanoHTTPD(int port) {\n        this(null, port);\n    }\n\n    // -------------------------------------------------------------------------------\n    // //\n    //\n    // Threading Strategy.\n    //\n    // -------------------------------------------------------------------------------\n    // //\n\n    /**\n     * Constructs an HTTP server on given hostname and port.\n     */\n    public NanoHTTPD(String hostname, int port) {\n        this.hostname = hostname;\n        this.myPort = port;\n        setTempFileManagerFactory(new DefaultTempFileManagerFactory());\n        setAsyncRunner(new DefaultAsyncRunner());\n\n        // creates a default handler that redirects to deprecated serve();\n        this.httpHandler = new IHandler<IHTTPSession, Response>() {\n\n            @Override\n            public Response handle(IHTTPSession input) {\n                return NanoHTTPD.this.serve(input);\n            }\n        };\n    }\n\n    public void setHTTPHandler(IHandler<IHTTPSession, Response> handler) {\n        this.httpHandler = handler;\n    }\n\n    public void addHTTPInterceptor(IHandler<IHTTPSession, Response> interceptor) {\n        interceptors.add(interceptor);\n    }\n\n    /**\n     * Forcibly closes all connections that are open.\n     */\n    public synchronized void closeAllConnections() {\n        stop();\n    }\n\n    /**\n     * create a instance of the client handler, subclasses can return a subclass\n     * of the ClientHandler.\n     * \n     * @param finalAccept\n     *            the socket the cleint is connected to\n     * @param inputStream\n     *            the input stream\n     * @return the client handler\n     */\n    protected ClientHandler createClientHandler(final Socket finalAccept, final InputStream inputStream) {\n        return new ClientHandler(this, inputStream, finalAccept);\n    }\n\n    /**\n     * Instantiate the server runnable, can be overwritten by subclasses to\n     * provide a subclass of the ServerRunnable.\n     * \n     * @param timeout\n     *            the socet timeout to use.\n     * @return the server runnable.\n     */\n    protected ServerRunnable createServerRunnable(final int timeout) {\n        return new ServerRunnable(this, timeout);\n    }\n\n    /**\n     * Decode parameters from a URL, handing the case where a single parameter\n     * name might have been supplied several times, by return lists of values.\n     * In general these lists will contain a single element.\n     * \n     * @param parms\n     *            original <b>NanoHTTPD</b> parameters values, as passed to the\n     *            <code>serve()</code> method.\n     * @return a map of <code>String</code> (parameter name) to\n     *         <code>List&lt;String&gt;</code> (a list of the values supplied).\n     */\n    protected static Map<String, List<String>> decodeParameters(Map<String, String> parms) {\n        return decodeParameters(parms.get(NanoHTTPD.QUERY_STRING_PARAMETER));\n    }\n\n    // -------------------------------------------------------------------------------\n    // //\n\n    /**\n     * Decode parameters from a URL, handing the case where a single parameter\n     * name might have been supplied several times, by return lists of values.\n     * In general these lists will contain a single element.\n     * \n     * @param queryString\n     *            a query string pulled from the URL.\n     * @return a map of <code>String</code> (parameter name) to\n     *         <code>List&lt;String&gt;</code> (a list of the values supplied).\n     */\n    protected static Map<String, List<String>> decodeParameters(String queryString) {\n        Map<String, List<String>> parms = new HashMap<String, List<String>>();\n        if (queryString != null) {\n            StringTokenizer st = new StringTokenizer(queryString, \"&\");\n            while (st.hasMoreTokens()) {\n                String e = st.nextToken();\n                int sep = e.indexOf('=');\n                String propertyName = sep >= 0 ? decodePercent(e.substring(0, sep)).trim() : decodePercent(e).trim();\n                if (!parms.containsKey(propertyName)) {\n                    parms.put(propertyName, new ArrayList<String>());\n                }\n                String propertyValue = sep >= 0 ? decodePercent(e.substring(sep + 1)) : null;\n                if (propertyValue != null) {\n                    parms.get(propertyName).add(propertyValue);\n                }\n            }\n        }\n        return parms;\n    }\n\n    /**\n     * Decode percent encoded <code>String</code> values.\n     * \n     * @param str\n     *            the percent encoded <code>String</code>\n     * @return expanded form of the input, for example \"foo%20bar\" becomes\n     *         \"foo bar\"\n     */\n    public static String decodePercent(String str) {\n        String decoded = null;\n        try {\n            decoded = URLDecoder.decode(str, \"UTF8\");\n        } catch (UnsupportedEncodingException ignored) {\n            NanoHTTPD.LOG.log(Level.WARNING, \"Encoding not supported, ignored\", ignored);\n        }\n        return decoded;\n    }\n\n    public final int getListeningPort() {\n        return this.myServerSocket == null ? -1 : this.myServerSocket.getLocalPort();\n    }\n\n    public final boolean isAlive() {\n        return wasStarted() && !this.myServerSocket.isClosed() && this.myThread.isAlive();\n    }\n\n    public IFactoryThrowing<ServerSocket, IOException> getServerSocketFactory() {\n        return serverSocketFactory;\n    }\n\n    public void setServerSocketFactory(IFactoryThrowing<ServerSocket, IOException> serverSocketFactory) {\n        this.serverSocketFactory = serverSocketFactory;\n    }\n\n    public String getHostname() {\n        return hostname;\n    }\n\n    public IFactory<ITempFileManager> getTempFileManagerFactory() {\n        return tempFileManagerFactory;\n    }\n\n    /**\n     * Call before start() to serve over HTTPS instead of HTTP\n     */\n    public void makeSecure(SSLServerSocketFactory sslServerSocketFactory, String[] sslProtocols) {\n        this.serverSocketFactory = new SecureServerSocketFactory(sslServerSocketFactory, sslProtocols);\n    }\n\n    /**\n     * This is the \"master\" method that delegates requests to handlers and makes\n     * sure there is a response to every request. You are not supposed to call\n     * or override this method in any circumstances. But no one will stop you if\n     * you do. I'm a Javadoc, not Code Police.\n     * \n     * @param session\n     *            the incoming session\n     * @return a response to the incoming session\n     */\n    public Response handle(IHTTPSession session) {\n        for (IHandler<IHTTPSession, Response> interceptor : interceptors) {\n            Response response = interceptor.handle(session);\n            if (response != null)\n                return response;\n        }\n        return httpHandler.handle(session);\n    }\n\n    /**\n     * Override this to customize the server.\n     * <p/>\n     * <p/>\n     * (By default, this returns a 404 \"Not Found\" plain text error response.)\n     * \n     * @param session\n     *            The HTTP session\n     * @return HTTP response, see class Response for details\n     */\n    @Deprecated\n    protected Response serve(IHTTPSession session) {\n        return Response.newFixedLengthResponse(Status.NOT_FOUND, NanoHTTPD.MIME_PLAINTEXT, \"Not Found\");\n    }\n\n    /**\n     * Pluggable strategy for asynchronously executing requests.\n     * \n     * @param asyncRunner\n     *            new strategy for handling threads.\n     */\n    public void setAsyncRunner(IAsyncRunner asyncRunner) {\n        this.asyncRunner = asyncRunner;\n    }\n\n    /**\n     * Pluggable strategy for creating and cleaning up temporary files.\n     * \n     * @param tempFileManagerFactory\n     *            new strategy for handling temp files.\n     */\n    public void setTempFileManagerFactory(IFactory<ITempFileManager> tempFileManagerFactory) {\n        this.tempFileManagerFactory = tempFileManagerFactory;\n    }\n\n    /**\n     * Start the server.\n     * \n     * @throws IOException\n     *             if the socket is in use.\n     */\n    public void start() throws IOException {\n        start(NanoHTTPD.SOCKET_READ_TIMEOUT);\n    }\n\n    /**\n     * Starts the server (in setDaemon(true) mode).\n     */\n    public void start(final int timeout) throws IOException {\n        start(timeout, true);\n    }\n\n    /**\n     * Start the server.\n     * \n     * @param timeout\n     *            timeout to use for socket connections.\n     * @param daemon\n     *            start the thread daemon or not.\n     * @throws IOException\n     *             if the socket is in use.\n     */\n    public void start(final int timeout, boolean daemon) throws IOException {\n        this.myServerSocket = this.getServerSocketFactory().create();\n        this.myServerSocket.setReuseAddress(true);\n\n        ServerRunnable serverRunnable = createServerRunnable(timeout);\n        this.myThread = new Thread(serverRunnable);\n        this.myThread.setDaemon(daemon);\n        this.myThread.setName(\"NanoHttpd Main Listener\");\n        this.myThread.start();\n        while (!serverRunnable.hasBinded() && serverRunnable.getBindException() == null) {\n            try {\n                Thread.sleep(10L);\n            } catch (Throwable e) {\n                // on android this may not be allowed, that's why we\n                // catch throwable the wait should be very short because we are\n                // just waiting for the bind of the socket\n            }\n        }\n        if (serverRunnable.getBindException() != null) {\n            throw serverRunnable.getBindException();\n        }\n    }\n\n    /**\n     * Stop the server.\n     */\n    public void stop() {\n        try {\n            safeClose(this.myServerSocket);\n            this.asyncRunner.closeAll();\n            if (this.myThread != null) {\n                this.myThread.join();\n            }\n        } catch (Exception e) {\n            NanoHTTPD.LOG.log(Level.SEVERE, \"Could not stop all connections\", e);\n        }\n    }\n\n    public final boolean wasStarted() {\n        return this.myServerSocket != null && this.myThread != null;\n    }\n}\n"
  },
  {
    "path": "core/src/main/java/org/nanohttpd/protocols/http/ServerRunnable.java",
    "content": "package org.nanohttpd.protocols.http;\n\n/*\n * #%L\n * NanoHttpd-Core\n * %%\n * Copyright (C) 2012 - 2016 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.net.InetSocketAddress;\nimport java.net.Socket;\nimport java.util.logging.Level;\n\n/**\n * The runnable that will be used for the main listening thread.\n */\npublic class ServerRunnable implements Runnable {\n\n    private NanoHTTPD httpd;\n\n    private final int timeout;\n\n    private IOException bindException;\n\n    private boolean hasBinded = false;\n\n    public ServerRunnable(NanoHTTPD httpd, int timeout) {\n        this.httpd = httpd;\n        this.timeout = timeout;\n    }\n\n    @Override\n    public void run() {\n        try {\n            httpd.getMyServerSocket().bind(httpd.hostname != null ? new InetSocketAddress(httpd.hostname, httpd.myPort) : new InetSocketAddress(httpd.myPort));\n            hasBinded = true;\n        } catch (IOException e) {\n            this.bindException = e;\n            return;\n        }\n        do {\n            try {\n                final Socket finalAccept = httpd.getMyServerSocket().accept();\n                if (this.timeout > 0) {\n                    finalAccept.setSoTimeout(this.timeout);\n                }\n                final InputStream inputStream = finalAccept.getInputStream();\n                httpd.asyncRunner.exec(httpd.createClientHandler(finalAccept, inputStream));\n            } catch (IOException e) {\n                NanoHTTPD.LOG.log(Level.FINE, \"Communication with the client broken\", e);\n            }\n        } while (!httpd.getMyServerSocket().isClosed());\n    }\n\n    public IOException getBindException() {\n        return bindException;\n    }\n\n    public boolean hasBinded() {\n        return hasBinded;\n    }\n}\n"
  },
  {
    "path": "core/src/main/java/org/nanohttpd/protocols/http/content/ContentType.java",
    "content": "package org.nanohttpd.protocols.http.content;\n\n/*\n * #%L\n * NanoHttpd-Core\n * %%\n * Copyright (C) 2012 - 2016 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\npublic class ContentType {\n\n    private static final String ASCII_ENCODING = \"US-ASCII\";\n\n    private static final String MULTIPART_FORM_DATA_HEADER = \"multipart/form-data\";\n\n    private static final String CONTENT_REGEX = \"[ |\\t]*([^/^ ^;^,]+/[^ ^;^,]+)\";\n\n    private static final Pattern MIME_PATTERN = Pattern.compile(CONTENT_REGEX, Pattern.CASE_INSENSITIVE);\n\n    private static final String CHARSET_REGEX = \"[ |\\t]*(charset)[ |\\t]*=[ |\\t]*['|\\\"]?([^\\\"^'^;^,]*)['|\\\"]?\";\n\n    private static final Pattern CHARSET_PATTERN = Pattern.compile(CHARSET_REGEX, Pattern.CASE_INSENSITIVE);\n\n    private static final String BOUNDARY_REGEX = \"[ |\\t]*(boundary)[ |\\t]*=[ |\\t]*['|\\\"]?([^\\\"^'^;^,]*)['|\\\"]?\";\n\n    private static final Pattern BOUNDARY_PATTERN = Pattern.compile(BOUNDARY_REGEX, Pattern.CASE_INSENSITIVE);\n\n    private final String contentTypeHeader;\n\n    private final String contentType;\n\n    private final String encoding;\n\n    private final String boundary;\n\n    public ContentType(String contentTypeHeader) {\n        this.contentTypeHeader = contentTypeHeader;\n        if (contentTypeHeader != null) {\n            contentType = getDetailFromContentHeader(contentTypeHeader, MIME_PATTERN, \"\", 1);\n            encoding = getDetailFromContentHeader(contentTypeHeader, CHARSET_PATTERN, null, 2);\n        } else {\n            contentType = \"\";\n            encoding = \"UTF-8\";\n        }\n        if (MULTIPART_FORM_DATA_HEADER.equalsIgnoreCase(contentType)) {\n            boundary = getDetailFromContentHeader(contentTypeHeader, BOUNDARY_PATTERN, null, 2);\n        } else {\n            boundary = null;\n        }\n    }\n\n    private String getDetailFromContentHeader(String contentTypeHeader, Pattern pattern, String defaultValue, int group) {\n        Matcher matcher = pattern.matcher(contentTypeHeader);\n        return matcher.find() ? matcher.group(group) : defaultValue;\n    }\n\n    public String getContentTypeHeader() {\n        return contentTypeHeader;\n    }\n\n    public String getContentType() {\n        return contentType;\n    }\n\n    public String getEncoding() {\n        return encoding == null ? ASCII_ENCODING : encoding;\n    }\n\n    public String getBoundary() {\n        return boundary;\n    }\n\n    public boolean isMultipart() {\n        return MULTIPART_FORM_DATA_HEADER.equalsIgnoreCase(contentType);\n    }\n\n    public ContentType tryUTF8() {\n        if (encoding == null) {\n            return new ContentType(this.contentTypeHeader + \"; charset=UTF-8\");\n        }\n        return this;\n    }\n}\n"
  },
  {
    "path": "core/src/main/java/org/nanohttpd/protocols/http/content/Cookie.java",
    "content": "package org.nanohttpd.protocols.http.content;\n\n/*\n * #%L\n * NanoHttpd-Core\n * %%\n * Copyright (C) 2012 - 2016 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport java.text.SimpleDateFormat;\nimport java.util.Calendar;\nimport java.util.Locale;\nimport java.util.TimeZone;\n\n/**\n * A simple cookie representation. This is old code and is flawed in many ways.\n * \n * @author LordFokas\n */\npublic class Cookie {\n\n    public static String getHTTPTime(int days) {\n        Calendar calendar = Calendar.getInstance();\n        SimpleDateFormat dateFormat = new SimpleDateFormat(\"EEE, dd MMM yyyy HH:mm:ss z\", Locale.US);\n        dateFormat.setTimeZone(TimeZone.getTimeZone(\"GMT\"));\n        calendar.add(Calendar.DAY_OF_MONTH, days);\n        return dateFormat.format(calendar.getTime());\n    }\n\n    private final String n, v, e;\n\n    public Cookie(String name, String value) {\n        this(name, value, 30);\n    }\n\n    public Cookie(String name, String value, int numDays) {\n        this.n = name;\n        this.v = value;\n        this.e = getHTTPTime(numDays);\n    }\n\n    public Cookie(String name, String value, String expires) {\n        this.n = name;\n        this.v = value;\n        this.e = expires;\n    }\n\n    public String getHTTPHeader() {\n        String fmt = \"%s=%s; expires=%s\";\n        return String.format(fmt, this.n, this.v, this.e);\n    }\n}\n"
  },
  {
    "path": "core/src/main/java/org/nanohttpd/protocols/http/content/CookieHandler.java",
    "content": "package org.nanohttpd.protocols.http.content;\n\n/*\n * #%L\n * NanoHttpd-Core\n * %%\n * Copyright (C) 2012 - 2016 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.Map;\n\nimport org.nanohttpd.protocols.http.response.Response;\n\n/**\n * Provides rudimentary support for cookies. Doesn't support 'path', 'secure'\n * nor 'httpOnly'. Feel free to improve it and/or add unsupported features. This\n * is old code and it's flawed in many ways.\n * \n * @author LordFokas\n */\npublic class CookieHandler implements Iterable<String> {\n\n    private final HashMap<String, String> cookies = new HashMap<String, String>();\n\n    private final ArrayList<Cookie> queue = new ArrayList<Cookie>();\n\n    public CookieHandler(Map<String, String> httpHeaders) {\n        String raw = httpHeaders.get(\"cookie\");\n        if (raw != null) {\n            String[] tokens = raw.split(\";\");\n            for (String token : tokens) {\n                String[] data = token.trim().split(\"=\");\n                if (data.length == 2) {\n                    this.cookies.put(data[0], data[1]);\n                }\n            }\n        }\n    }\n\n    /**\n     * Set a cookie with an expiration date from a month ago, effectively\n     * deleting it on the client side.\n     * \n     * @param name\n     *            The cookie name.\n     */\n    public void delete(String name) {\n        set(name, \"-delete-\", -30);\n    }\n\n    @Override\n    public Iterator<String> iterator() {\n        return this.cookies.keySet().iterator();\n    }\n\n    /**\n     * Read a cookie from the HTTP Headers.\n     * \n     * @param name\n     *            The cookie's name.\n     * @return The cookie's value if it exists, null otherwise.\n     */\n    public String read(String name) {\n        return this.cookies.get(name);\n    }\n\n    public void set(Cookie cookie) {\n        this.queue.add(cookie);\n    }\n\n    /**\n     * Sets a cookie.\n     * \n     * @param name\n     *            The cookie's name.\n     * @param value\n     *            The cookie's value.\n     * @param expires\n     *            How many days until the cookie expires.\n     */\n    public void set(String name, String value, int expires) {\n        this.queue.add(new Cookie(name, value, Cookie.getHTTPTime(expires)));\n    }\n\n    /**\n     * Internally used by the webserver to add all queued cookies into the\n     * Response's HTTP Headers.\n     * \n     * @param response\n     *            The Response object to which headers the queued cookies will\n     *            be added.\n     */\n    public void unloadQueue(Response response) {\n        for (Cookie cookie : this.queue) {\n            response.addCookieHeader(cookie.getHTTPHeader());\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/main/java/org/nanohttpd/protocols/http/request/Method.java",
    "content": "package org.nanohttpd.protocols.http.request;\n\n/*\n * #%L\n * NanoHttpd-Core\n * %%\n * Copyright (C) 2012 - 2016 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\n/**\n * HTTP Request methods, with the ability to decode a <code>String</code> back\n * to its enum value.\n */\npublic enum Method {\n    GET,\n    PUT,\n    POST,\n    DELETE,\n    HEAD,\n    OPTIONS,\n    TRACE,\n    CONNECT,\n    PATCH,\n    PROPFIND,\n    PROPPATCH,\n    MKCOL,\n    MOVE,\n    COPY,\n    LOCK,\n    UNLOCK,\n    NOTIFY,\n    SUBSCRIBE;\n\n    public static Method lookup(String method) {\n        if (method == null)\n            return null;\n\n        try {\n            return valueOf(method);\n        } catch (IllegalArgumentException e) {\n            // TODO: Log it?\n            return null;\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/main/java/org/nanohttpd/protocols/http/response/ChunkedOutputStream.java",
    "content": "package org.nanohttpd.protocols.http.response;\n\n/*\n * #%L\n * NanoHttpd-Core\n * %%\n * Copyright (C) 2012 - 2016 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport java.io.FilterOutputStream;\nimport java.io.IOException;\nimport java.io.OutputStream;\n\n/**\n * Output stream that will automatically send every write to the wrapped\n * OutputStream according to chunked transfer:\n * http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.6.1\n */\npublic class ChunkedOutputStream extends FilterOutputStream {\n\n    public ChunkedOutputStream(OutputStream out) {\n        super(out);\n    }\n\n    @Override\n    public void write(int b) throws IOException {\n        byte[] data = {\n            (byte) b\n        };\n        write(data, 0, 1);\n    }\n\n    @Override\n    public void write(byte[] b) throws IOException {\n        write(b, 0, b.length);\n    }\n\n    @Override\n    public void write(byte[] b, int off, int len) throws IOException {\n        if (len == 0)\n            return;\n        out.write(String.format(\"%x\\r\\n\", len).getBytes());\n        out.write(b, off, len);\n        out.write(\"\\r\\n\".getBytes());\n    }\n\n    public void finish() throws IOException {\n        out.write(\"0\\r\\n\\r\\n\".getBytes());\n    }\n}\n"
  },
  {
    "path": "core/src/main/java/org/nanohttpd/protocols/http/response/IStatus.java",
    "content": "package org.nanohttpd.protocols.http.response;\n\n/*\n * #%L\n * NanoHttpd-Core\n * %%\n * Copyright (C) 2012 - 2016 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\npublic interface IStatus {\n\n    String getDescription();\n\n    int getRequestStatus();\n}\n"
  },
  {
    "path": "core/src/main/java/org/nanohttpd/protocols/http/response/Response.java",
    "content": "package org.nanohttpd.protocols.http.response;\n\n/*\n * #%L\n * NanoHttpd-Core\n * %%\n * Copyright (C) 2012 - 2016 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport java.io.BufferedWriter;\nimport java.io.ByteArrayInputStream;\nimport java.io.Closeable;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.io.OutputStreamWriter;\nimport java.io.PrintWriter;\nimport java.io.UnsupportedEncodingException;\nimport java.nio.charset.Charset;\nimport java.nio.charset.CharsetEncoder;\nimport java.text.SimpleDateFormat;\nimport java.util.ArrayList;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.TimeZone;\nimport java.util.logging.Level;\nimport java.util.zip.GZIPOutputStream;\n\nimport org.nanohttpd.protocols.http.NanoHTTPD;\nimport org.nanohttpd.protocols.http.content.ContentType;\nimport org.nanohttpd.protocols.http.request.Method;\n\n/**\n * HTTP response. Return one of these from serve().\n */\npublic class Response implements Closeable {\n\n    /**\n     * HTTP status code after processing, e.g. \"200 OK\", Status.OK\n     */\n    private IStatus status;\n\n    /**\n     * MIME type of content, e.g. \"text/html\"\n     */\n    private String mimeType;\n\n    /**\n     * Data of the response, may be null.\n     */\n    private InputStream data;\n\n    private long contentLength;\n\n    /**\n     * Headers for the HTTP response. Use addHeader() to add lines. the\n     * lowercase map is automatically kept up to date.\n     */\n    @SuppressWarnings(\"serial\")\n    private final Map<String, String> header = new HashMap<String, String>() {\n\n        public String put(String key, String value) {\n            lowerCaseHeader.put(key == null ? key : key.toLowerCase(), value);\n            return super.put(key, value);\n        };\n    };\n\n    /**\n     * copy of the header map with all the keys lowercase for faster searching.\n     */\n    private final Map<String, String> lowerCaseHeader = new HashMap<String, String>();\n\n    /**\n     * The request method that spawned this response.\n     */\n    private Method requestMethod;\n\n    /**\n     * Use chunkedTransfer\n     */\n    private boolean chunkedTransfer;\n\n    private boolean keepAlive;\n\n    private List<String> cookieHeaders;\n\n    private GzipUsage gzipUsage = GzipUsage.DEFAULT;\n\n    private static enum GzipUsage {\n        DEFAULT,\n        ALWAYS,\n        NEVER;\n    }\n\n    /**\n     * Creates a fixed length response if totalBytes>=0, otherwise chunked.\n     */\n    @SuppressWarnings({\n        \"rawtypes\",\n        \"unchecked\"\n    })\n    protected Response(IStatus status, String mimeType, InputStream data, long totalBytes) {\n        this.status = status;\n        this.mimeType = mimeType;\n        if (data == null) {\n            this.data = new ByteArrayInputStream(new byte[0]);\n            this.contentLength = 0L;\n        } else {\n            this.data = data;\n            this.contentLength = totalBytes;\n        }\n        this.chunkedTransfer = this.contentLength < 0;\n        this.keepAlive = true;\n        this.cookieHeaders = new ArrayList(10);\n    }\n\n    @Override\n    public void close() throws IOException {\n        if (this.data != null) {\n            this.data.close();\n        }\n    }\n\n    /**\n     * Adds a cookie header to the list. Should not be called manually, this is\n     * an internal utility.\n     */\n    public void addCookieHeader(String cookie) {\n        cookieHeaders.add(cookie);\n    }\n\n    /**\n     * Should not be called manually. This is an internally utility for JUnit\n     * test purposes.\n     * \n     * @return All unloaded cookie headers.\n     */\n    public List<String> getCookieHeaders() {\n        return cookieHeaders;\n    }\n\n    /**\n     * Adds given line to the header.\n     */\n    public void addHeader(String name, String value) {\n        this.header.put(name, value);\n    }\n\n    /**\n     * Indicate to close the connection after the Response has been sent.\n     * \n     * @param close\n     *            {@code true} to hint connection closing, {@code false} to let\n     *            connection be closed by client.\n     */\n    public void closeConnection(boolean close) {\n        if (close)\n            this.header.put(\"connection\", \"close\");\n        else\n            this.header.remove(\"connection\");\n    }\n\n    /**\n     * @return {@code true} if connection is to be closed after this Response\n     *         has been sent.\n     */\n    public boolean isCloseConnection() {\n        return \"close\".equals(getHeader(\"connection\"));\n    }\n\n    public InputStream getData() {\n        return this.data;\n    }\n\n    public String getHeader(String name) {\n        return this.lowerCaseHeader.get(name.toLowerCase());\n    }\n\n    public String getMimeType() {\n        return this.mimeType;\n    }\n\n    public Method getRequestMethod() {\n        return this.requestMethod;\n    }\n\n    public IStatus getStatus() {\n        return this.status;\n    }\n\n    public void setKeepAlive(boolean useKeepAlive) {\n        this.keepAlive = useKeepAlive;\n    }\n\n    /**\n     * Sends given response to the socket.\n     */\n    public void send(OutputStream outputStream) {\n        SimpleDateFormat gmtFrmt = new SimpleDateFormat(\"E, d MMM yyyy HH:mm:ss 'GMT'\", Locale.US);\n        gmtFrmt.setTimeZone(TimeZone.getTimeZone(\"GMT\"));\n\n        try {\n            if (this.status == null) {\n                throw new Error(\"sendResponse(): Status can't be null.\");\n            }\n            PrintWriter pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(outputStream, new ContentType(this.mimeType).getEncoding())), false);\n            pw.append(\"HTTP/1.1 \").append(this.status.getDescription()).append(\" \\r\\n\");\n            if (this.mimeType != null) {\n                printHeader(pw, \"Content-Type\", this.mimeType);\n            }\n            if (getHeader(\"date\") == null) {\n                printHeader(pw, \"Date\", gmtFrmt.format(new Date()));\n            }\n            for (Entry<String, String> entry : this.header.entrySet()) {\n                printHeader(pw, entry.getKey(), entry.getValue());\n            }\n            for (String cookieHeader : this.cookieHeaders) {\n                printHeader(pw, \"Set-Cookie\", cookieHeader);\n            }\n            if (getHeader(\"connection\") == null) {\n                printHeader(pw, \"Connection\", (this.keepAlive ? \"keep-alive\" : \"close\"));\n            }\n            if (getHeader(\"content-length\") != null) {\n                setUseGzip(false);\n            }\n            if (useGzipWhenAccepted()) {\n                printHeader(pw, \"Content-Encoding\", \"gzip\");\n                setChunkedTransfer(true);\n            }\n            long pending = this.data != null ? this.contentLength : 0;\n            if (this.requestMethod != Method.HEAD && this.chunkedTransfer) {\n                printHeader(pw, \"Transfer-Encoding\", \"chunked\");\n            } else if (!useGzipWhenAccepted()) {\n                pending = sendContentLengthHeaderIfNotAlreadyPresent(pw, pending);\n            }\n            pw.append(\"\\r\\n\");\n            pw.flush();\n            sendBodyWithCorrectTransferAndEncoding(outputStream, pending);\n            outputStream.flush();\n            NanoHTTPD.safeClose(this.data);\n        } catch (IOException ioe) {\n            NanoHTTPD.LOG.log(Level.SEVERE, \"Could not send response to the client\", ioe);\n        }\n    }\n\n    @SuppressWarnings(\"static-method\")\n    protected void printHeader(PrintWriter pw, String key, String value) {\n        pw.append(key).append(\": \").append(value).append(\"\\r\\n\");\n    }\n\n    protected long sendContentLengthHeaderIfNotAlreadyPresent(PrintWriter pw, long defaultSize) {\n        String contentLengthString = getHeader(\"content-length\");\n        long size = defaultSize;\n        if (contentLengthString != null) {\n            try {\n                size = Long.parseLong(contentLengthString);\n            } catch (NumberFormatException ex) {\n                NanoHTTPD.LOG.severe(\"content-length was no number \" + contentLengthString);\n            }\n        }else{\n        \tpw.print(\"Content-Length: \" + size + \"\\r\\n\");\n        }\n        return size;\n    }\n\n    private void sendBodyWithCorrectTransferAndEncoding(OutputStream outputStream, long pending) throws IOException {\n        if (this.requestMethod != Method.HEAD && this.chunkedTransfer) {\n            ChunkedOutputStream chunkedOutputStream = new ChunkedOutputStream(outputStream);\n            sendBodyWithCorrectEncoding(chunkedOutputStream, -1);\n            try {\n                chunkedOutputStream.finish();\n            } catch (Exception e) {\n                if(this.data != null) {\n                    this.data.close();\n                }\n            }\n        } else {\n            sendBodyWithCorrectEncoding(outputStream, pending);\n        }\n    }\n\n    private void sendBodyWithCorrectEncoding(OutputStream outputStream, long pending) throws IOException {\n        if (useGzipWhenAccepted()) {\n            GZIPOutputStream gzipOutputStream = null;\n            try {\n                gzipOutputStream = new GZIPOutputStream(outputStream);\n            } catch (Exception e) {\n                if(this.data != null) {\n                    this.data.close();\n                }\n            }\n            if (gzipOutputStream != null) {\n                sendBody(gzipOutputStream, -1);\n                gzipOutputStream.finish();\n            }\n        } else {\n            sendBody(outputStream, pending);\n        }\n    }\n\n    /**\n     * Sends the body to the specified OutputStream. The pending parameter\n     * limits the maximum amounts of bytes sent unless it is -1, in which case\n     * everything is sent.\n     * \n     * @param outputStream\n     *            the OutputStream to send data to\n     * @param pending\n     *            -1 to send everything, otherwise sets a max limit to the\n     *            number of bytes sent\n     * @throws IOException\n     *             if something goes wrong while sending the data.\n     */\n    private void sendBody(OutputStream outputStream, long pending) throws IOException {\n        long BUFFER_SIZE = 16 * 1024;\n        byte[] buff = new byte[(int) BUFFER_SIZE];\n        boolean sendEverything = pending == -1;\n        while (pending > 0 || sendEverything) {\n            long bytesToRead = sendEverything ? BUFFER_SIZE : Math.min(pending, BUFFER_SIZE);\n            int read = this.data.read(buff, 0, (int) bytesToRead);\n            if (read <= 0) {\n                break;\n            }\n            try {\n                outputStream.write(buff, 0, read);\n            } catch (Exception e) {\n                if(this.data != null) {\n                    this.data.close();\n                }\n            }\n            if (!sendEverything) {\n                pending -= read;\n            }\n        }\n    }\n\n    public void setChunkedTransfer(boolean chunkedTransfer) {\n        this.chunkedTransfer = chunkedTransfer;\n    }\n\n    public void setData(InputStream data) {\n        this.data = data;\n    }\n\n    public void setMimeType(String mimeType) {\n        this.mimeType = mimeType;\n    }\n\n    public void setRequestMethod(Method requestMethod) {\n        this.requestMethod = requestMethod;\n    }\n\n    public void setStatus(IStatus status) {\n        this.status = status;\n    }\n\n    /**\n     * Create a response with unknown length (using HTTP 1.1 chunking).\n     */\n    public static Response newChunkedResponse(IStatus status, String mimeType, InputStream data) {\n        return new Response(status, mimeType, data, -1);\n    }\n\n    public static Response newFixedLengthResponse(IStatus status, String mimeType, byte[] data) {\n        return newFixedLengthResponse(status, mimeType, new ByteArrayInputStream(data), data.length);\n    }\n\n    /**\n     * Create a response with known length.\n     */\n    public static Response newFixedLengthResponse(IStatus status, String mimeType, InputStream data, long totalBytes) {\n        return new Response(status, mimeType, data, totalBytes);\n    }\n\n    /**\n     * Create a text response with known length.\n     */\n    public static Response newFixedLengthResponse(IStatus status, String mimeType, String txt) {\n        ContentType contentType = new ContentType(mimeType);\n        if (txt == null) {\n            return newFixedLengthResponse(status, mimeType, new ByteArrayInputStream(new byte[0]), 0);\n        } else {\n            byte[] bytes;\n            try {\n                CharsetEncoder newEncoder = Charset.forName(contentType.getEncoding()).newEncoder();\n                if (!newEncoder.canEncode(txt)) {\n                    contentType = contentType.tryUTF8();\n                }\n                bytes = txt.getBytes(contentType.getEncoding());\n            } catch (UnsupportedEncodingException e) {\n                NanoHTTPD.LOG.log(Level.SEVERE, \"encoding problem, responding nothing\", e);\n                bytes = new byte[0];\n            }\n            return newFixedLengthResponse(status, contentType.getContentTypeHeader(), new ByteArrayInputStream(bytes), bytes.length);\n        }\n    }\n\n    /**\n     * Create a text response with known length.\n     */\n    public static Response newFixedLengthResponse(String msg) {\n        return newFixedLengthResponse(Status.OK, NanoHTTPD.MIME_HTML, msg);\n    }\n\n    public Response setUseGzip(boolean useGzip) {\n        gzipUsage = useGzip ? GzipUsage.ALWAYS : GzipUsage.NEVER;\n        return this;\n    }\n\n    // If a Gzip usage has been enforced, use it.\n    // Else decide whether or not to use Gzip.\n    public boolean useGzipWhenAccepted() {\n        if (gzipUsage == GzipUsage.DEFAULT)\n            return getMimeType() != null && (getMimeType().toLowerCase().contains(\"text/\") || getMimeType().toLowerCase().contains(\"/json\"));\n        else\n            return gzipUsage == GzipUsage.ALWAYS;\n    }\n}\n"
  },
  {
    "path": "core/src/main/java/org/nanohttpd/protocols/http/response/Status.java",
    "content": "package org.nanohttpd.protocols.http.response;\n\n/*\n * #%L\n * NanoHttpd-Core\n * %%\n * Copyright (C) 2012 - 2016 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\n/**\n * Some HTTP response status codes\n */\npublic enum Status implements IStatus {\n    SWITCH_PROTOCOL(101, \"Switching Protocols\"),\n\n    OK(200, \"OK\"),\n    CREATED(201, \"Created\"),\n    ACCEPTED(202, \"Accepted\"),\n    NO_CONTENT(204, \"No Content\"),\n    PARTIAL_CONTENT(206, \"Partial Content\"),\n    MULTI_STATUS(207, \"Multi-Status\"),\n\n    REDIRECT(301, \"Moved Permanently\"),\n    /**\n     * Many user agents mishandle 302 in ways that violate the RFC1945 spec\n     * (i.e., redirect a POST to a GET). 303 and 307 were added in RFC2616 to\n     * address this. You should prefer 303 and 307 unless the calling user agent\n     * does not support 303 and 307 functionality\n     */\n    @Deprecated\n    FOUND(302, \"Found\"),\n    REDIRECT_SEE_OTHER(303, \"See Other\"),\n    NOT_MODIFIED(304, \"Not Modified\"),\n    TEMPORARY_REDIRECT(307, \"Temporary Redirect\"),\n\n    BAD_REQUEST(400, \"Bad Request\"),\n    UNAUTHORIZED(401, \"Unauthorized\"),\n    FORBIDDEN(403, \"Forbidden\"),\n    NOT_FOUND(404, \"Not Found\"),\n    METHOD_NOT_ALLOWED(405, \"Method Not Allowed\"),\n    NOT_ACCEPTABLE(406, \"Not Acceptable\"),\n    REQUEST_TIMEOUT(408, \"Request Timeout\"),\n    CONFLICT(409, \"Conflict\"),\n    GONE(410, \"Gone\"),\n    LENGTH_REQUIRED(411, \"Length Required\"),\n    PRECONDITION_FAILED(412, \"Precondition Failed\"),\n    PAYLOAD_TOO_LARGE(413, \"Payload Too Large\"),\n    UNSUPPORTED_MEDIA_TYPE(415, \"Unsupported Media Type\"),\n    RANGE_NOT_SATISFIABLE(416, \"Requested Range Not Satisfiable\"),\n    EXPECTATION_FAILED(417, \"Expectation Failed\"),\n    TOO_MANY_REQUESTS(429, \"Too Many Requests\"),\n\n    INTERNAL_ERROR(500, \"Internal Server Error\"),\n    NOT_IMPLEMENTED(501, \"Not Implemented\"),\n    SERVICE_UNAVAILABLE(503, \"Service Unavailable\"),\n    UNSUPPORTED_HTTP_VERSION(505, \"HTTP Version Not Supported\");\n\n    private final int requestStatus;\n\n    private final String description;\n\n    Status(int requestStatus, String description) {\n        this.requestStatus = requestStatus;\n        this.description = description;\n    }\n\n    public static Status lookup(int requestStatus) {\n        for (Status status : Status.values()) {\n            if (status.getRequestStatus() == requestStatus) {\n                return status;\n            }\n        }\n        return null;\n    }\n\n    @Override\n    public String getDescription() {\n        return \"\" + this.requestStatus + \" \" + this.description;\n    }\n\n    @Override\n    public int getRequestStatus() {\n        return this.requestStatus;\n    }\n}\n"
  },
  {
    "path": "core/src/main/java/org/nanohttpd/protocols/http/sockets/DefaultServerSocketFactory.java",
    "content": "package org.nanohttpd.protocols.http.sockets;\n\n/*\n * #%L\n * NanoHttpd-Core\n * %%\n * Copyright (C) 2012 - 2016 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport java.io.IOException;\nimport java.net.ServerSocket;\n\nimport org.nanohttpd.util.IFactoryThrowing;\n\n/**\n * Creates a normal ServerSocket for TCP connections\n */\npublic class DefaultServerSocketFactory implements IFactoryThrowing<ServerSocket, IOException> {\n\n    @Override\n    public ServerSocket create() throws IOException {\n        return new ServerSocket();\n    }\n\n}\n"
  },
  {
    "path": "core/src/main/java/org/nanohttpd/protocols/http/sockets/SecureServerSocketFactory.java",
    "content": "package org.nanohttpd.protocols.http.sockets;\n\n/*\n * #%L\n * NanoHttpd-Core\n * %%\n * Copyright (C) 2012 - 2016 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport java.io.IOException;\nimport java.net.ServerSocket;\n\nimport javax.net.ssl.SSLServerSocket;\nimport javax.net.ssl.SSLServerSocketFactory;\n\nimport org.nanohttpd.util.IFactoryThrowing;\n\n/**\n * Creates a new SSLServerSocket\n */\npublic class SecureServerSocketFactory implements IFactoryThrowing<ServerSocket, IOException> {\n\n    private SSLServerSocketFactory sslServerSocketFactory;\n\n    private String[] sslProtocols;\n\n    public SecureServerSocketFactory(SSLServerSocketFactory sslServerSocketFactory, String[] sslProtocols) {\n        this.sslServerSocketFactory = sslServerSocketFactory;\n        this.sslProtocols = sslProtocols;\n    }\n\n    @Override\n    public ServerSocket create() throws IOException {\n        SSLServerSocket ss = null;\n        ss = (SSLServerSocket) this.sslServerSocketFactory.createServerSocket();\n        if (this.sslProtocols != null) {\n            ss.setEnabledProtocols(this.sslProtocols);\n        } else {\n            ss.setEnabledProtocols(ss.getSupportedProtocols());\n        }\n        ss.setUseClientMode(false);\n        ss.setWantClientAuth(false);\n        ss.setNeedClientAuth(false);\n        return ss;\n    }\n\n}\n"
  },
  {
    "path": "core/src/main/java/org/nanohttpd/protocols/http/tempfiles/DefaultTempFile.java",
    "content": "package org.nanohttpd.protocols.http.tempfiles;\n\n/*\n * #%L\n * NanoHttpd-Core\n * %%\n * Copyright (C) 2012 - 2016 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.OutputStream;\n\nimport org.nanohttpd.protocols.http.NanoHTTPD;\n\n/**\n * Default strategy for creating and cleaning up temporary files.\n * <p/>\n * <p>\n * By default, files are created by <code>File.createTempFile()</code> in the\n * directory specified.\n * </p>\n */\npublic class DefaultTempFile implements ITempFile {\n\n    private final File file;\n\n    private final OutputStream fstream;\n\n    public DefaultTempFile(File tempdir) throws IOException {\n        this.file = File.createTempFile(\"NanoHTTPD-\", \"\", tempdir);\n        this.fstream = new FileOutputStream(this.file);\n    }\n\n    @Override\n    public void delete() throws Exception {\n        NanoHTTPD.safeClose(this.fstream);\n        if (!this.file.delete()) {\n            throw new Exception(\"could not delete temporary file: \" + this.file.getAbsolutePath());\n        }\n    }\n\n    @Override\n    public String getName() {\n        return this.file.getAbsolutePath();\n    }\n\n    @Override\n    public OutputStream open() throws Exception {\n        return this.fstream;\n    }\n}\n"
  },
  {
    "path": "core/src/main/java/org/nanohttpd/protocols/http/tempfiles/DefaultTempFileManager.java",
    "content": "package org.nanohttpd.protocols.http.tempfiles;\n\n/*\n * #%L\n * NanoHttpd-Core\n * %%\n * Copyright (C) 2012 - 2016 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport java.io.File;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.logging.Level;\n\nimport org.nanohttpd.protocols.http.NanoHTTPD;\n\n/**\n * Default strategy for creating and cleaning up temporary files.\n * <p/>\n * <p>\n * This class stores its files in the standard location (that is, wherever\n * <code>java.io.tmpdir</code> points to). Files are added to an internal list,\n * and deleted when no longer needed (that is, when <code>clear()</code> is\n * invoked at the end of processing a request).\n * </p>\n */\npublic class DefaultTempFileManager implements ITempFileManager {\n\n    private final File tmpdir;\n\n    private final List<ITempFile> tempFiles;\n\n    public DefaultTempFileManager() {\n        this.tmpdir = new File(System.getProperty(\"java.io.tmpdir\"));\n        if (!tmpdir.exists()) {\n            tmpdir.mkdirs();\n        }\n        this.tempFiles = new ArrayList<ITempFile>();\n    }\n\n    @Override\n    public void clear() {\n        for (ITempFile file : this.tempFiles) {\n            try {\n                file.delete();\n            } catch (Exception ignored) {\n                NanoHTTPD.LOG.log(Level.WARNING, \"could not delete file \", ignored);\n            }\n        }\n        this.tempFiles.clear();\n    }\n\n    @Override\n    public ITempFile createTempFile(String filename_hint) throws Exception {\n        DefaultTempFile tempFile = new DefaultTempFile(this.tmpdir);\n        this.tempFiles.add(tempFile);\n        return tempFile;\n    }\n}\n"
  },
  {
    "path": "core/src/main/java/org/nanohttpd/protocols/http/tempfiles/DefaultTempFileManagerFactory.java",
    "content": "package org.nanohttpd.protocols.http.tempfiles;\n\n/*\n * #%L\n * NanoHttpd-Core\n * %%\n * Copyright (C) 2012 - 2016 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport org.nanohttpd.util.IFactory;\n\n/**\n * Default strategy for creating and cleaning up temporary files.\n */\npublic class DefaultTempFileManagerFactory implements IFactory<ITempFileManager> {\n\n    @Override\n    public ITempFileManager create() {\n        return new DefaultTempFileManager();\n    }\n}\n"
  },
  {
    "path": "core/src/main/java/org/nanohttpd/protocols/http/tempfiles/ITempFile.java",
    "content": "package org.nanohttpd.protocols.http.tempfiles;\n\n/*\n * #%L\n * NanoHttpd-Core\n * %%\n * Copyright (C) 2012 - 2016 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport java.io.OutputStream;\n\n/**\n * A temp file.\n * <p/>\n * <p>\n * Temp files are responsible for managing the actual temporary storage and\n * cleaning themselves up when no longer needed.\n * </p>\n */\npublic interface ITempFile {\n\n    public void delete() throws Exception;\n\n    public String getName();\n\n    public OutputStream open() throws Exception;\n}\n"
  },
  {
    "path": "core/src/main/java/org/nanohttpd/protocols/http/tempfiles/ITempFileManager.java",
    "content": "package org.nanohttpd.protocols.http.tempfiles;\n\n/*\n * #%L\n * NanoHttpd-Core\n * %%\n * Copyright (C) 2012 - 2016 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\n/**\n * Temp file manager.\n * <p/>\n * <p>\n * Temp file managers are created 1-to-1 with incoming requests, to create and\n * cleanup temporary files created as a result of handling the request.\n * </p>\n */\npublic interface ITempFileManager {\n\n    void clear();\n\n    public ITempFile createTempFile(String filename_hint) throws Exception;\n}\n"
  },
  {
    "path": "core/src/main/java/org/nanohttpd/protocols/http/threading/DefaultAsyncRunner.java",
    "content": "package org.nanohttpd.protocols.http.threading;\n\n/*\n * #%L\n * NanoHttpd-Core\n * %%\n * Copyright (C) 2012 - 2016 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\nimport org.nanohttpd.protocols.http.ClientHandler;\n\n/**\n * Default threading strategy for NanoHTTPD.\n * <p/>\n * <p>\n * By default, the server spawns a new Thread for every incoming request. These\n * are set to <i>daemon</i> status, and named according to the request number.\n * The name is useful when profiling the application.\n * </p>\n */\npublic class DefaultAsyncRunner implements IAsyncRunner {\n\n    protected long requestCount;\n\n    private final List<ClientHandler> running = Collections.synchronizedList(new ArrayList<ClientHandler>());\n\n    /**\n     * @return a list with currently running clients.\n     */\n    public List<ClientHandler> getRunning() {\n        return running;\n    }\n\n    @Override\n    public void closeAll() {\n        // copy of the list for concurrency\n        for (ClientHandler clientHandler : new ArrayList<ClientHandler>(this.running)) {\n            clientHandler.close();\n        }\n    }\n\n    @Override\n    public void closed(ClientHandler clientHandler) {\n        this.running.remove(clientHandler);\n    }\n\n    @Override\n    public void exec(ClientHandler clientHandler) {\n        ++this.requestCount;\n        this.running.add(clientHandler);\n        createThread(clientHandler).start();\n    }\n\n    protected Thread createThread(ClientHandler clientHandler) {\n        Thread t = new Thread(clientHandler);\n        t.setDaemon(true);\n        t.setName(\"NanoHttpd Request Processor (#\" + this.requestCount + \")\");\n        return t;\n    }\n}\n"
  },
  {
    "path": "core/src/main/java/org/nanohttpd/protocols/http/threading/IAsyncRunner.java",
    "content": "package org.nanohttpd.protocols.http.threading;\n\n/*\n * #%L\n * NanoHttpd-Core\n * %%\n * Copyright (C) 2012 - 2016 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport org.nanohttpd.protocols.http.ClientHandler;\n\n/**\n * Pluggable strategy for asynchronously executing requests.\n */\npublic interface IAsyncRunner {\n\n    void closeAll();\n\n    void closed(ClientHandler clientHandler);\n\n    void exec(ClientHandler code);\n}\n"
  },
  {
    "path": "core/src/main/java/org/nanohttpd/util/IFactory.java",
    "content": "package org.nanohttpd.util;\n\n/*\n * #%L\n * NanoHttpd-Core\n * %%\n * Copyright (C) 2012 - 2016 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\n/**\n * Represents a simple factory\n * \n * @author LordFokas\n * @param <T>\n *            The Type of object to create\n */\npublic interface IFactory<T> {\n\n    T create();\n}\n"
  },
  {
    "path": "core/src/main/java/org/nanohttpd/util/IFactoryThrowing.java",
    "content": "package org.nanohttpd.util;\n\n/*\n * #%L\n * NanoHttpd-Core\n * %%\n * Copyright (C) 2012 - 2016 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\n/**\n * Represents a factory that can throw an exception instead of actually creating\n * an object\n * \n * @author LordFokas\n * @param <T>\n *            The Type of object to create\n * @param <E>\n *            The base Type of exceptions that can be thrown\n */\npublic interface IFactoryThrowing<T, E extends Throwable> {\n\n    T create() throws E;\n}\n"
  },
  {
    "path": "core/src/main/java/org/nanohttpd/util/IHandler.java",
    "content": "package org.nanohttpd.util;\n\n/*\n * #%L\n * NanoHttpd-Core\n * %%\n * Copyright (C) 2012 - 2016 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\n/**\n * Defines a generic handler that returns an object of type O when given an\n * object of type I.\n * \n * @author LordFokas\n * @param <I>\n *            The input type.\n * @param <O>\n *            The output type.\n */\npublic interface IHandler<I, O> {\n\n    public O handle(I input);\n}\n"
  },
  {
    "path": "core/src/main/java/org/nanohttpd/util/ServerRunner.java",
    "content": "package org.nanohttpd.util;\n\n/*\n * #%L\n * NanoHttpd-Webserver\n * %%\n * Copyright (C) 2012 - 2015 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport java.io.IOException;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\nimport org.nanohttpd.protocols.http.NanoHTTPD;\n\npublic class ServerRunner {\n\n    /**\n     * logger to log to.\n     */\n    private static final Logger LOG = Logger.getLogger(ServerRunner.class.getName());\n\n    public static void executeInstance(NanoHTTPD server) {\n        try {\n            server.start(NanoHTTPD.SOCKET_READ_TIMEOUT, false);\n        } catch (IOException ioe) {\n            System.err.println(\"Couldn't start server:\\n\" + ioe);\n            System.exit(-1);\n        }\n\n        System.out.println(\"Server started, Hit Enter to stop.\\n\");\n\n        try {\n            System.in.read();\n        } catch (Throwable ignored) {\n        }\n\n        server.stop();\n        System.out.println(\"Server stopped.\\n\");\n    }\n\n    public static <T extends NanoHTTPD> void run(Class<T> serverClass) {\n        try {\n            executeInstance(serverClass.newInstance());\n        } catch (Exception e) {\n            ServerRunner.LOG.log(Level.SEVERE, \"Could not create server\", e);\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/main/resources/META-INF/nanohttpd/default-mimetypes.properties",
    "content": "#default mime types for nanohttpd, use META-INF/mimetypes.properties for user defined mimetypes\ncss=text/css\nhtm=text/html\nhtml=text/html\nxml=text/xml\njava=text/x-java-source, text/java\nmd=text/plain\ntxt=text/plain\nasc=text/plain\ngif=image/gif\njpg=image/jpeg\njpeg=image/jpeg\npng=image/png\nsvg=image/svg+xml\nmp3=audio/mpeg\nm3u=audio/mpeg-url\nmp4=video/mp4\nogv=video/ogg\nflv=video/x-flv\nmov=video/quicktime\nswf=application/x-shockwave-flash\njs=application/javascript\npdf=application/pdf\ndoc=application/msword\nogg=application/x-ogg\nzip=application/octet-stream\nexe=application/octet-stream\nclass=application/octet-stream\nm3u8=application/vnd.apple.mpegurl\nts=video/mp2t"
  },
  {
    "path": "core/src/main/resources/META-INF/nanohttpd/mimetypes.properties",
    "content": "#mime types for nanohttpd, use a file like this for user defined mimetypes"
  },
  {
    "path": "core/src/site/site.xml",
    "content": "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n<project name=\"${project.name}\">\n\t<skin>\n\t\t<groupId>org.apache.maven.skins</groupId>\n\t\t<artifactId>maven-fluido-skin</artifactId>\n\t\t<version>1.3.0</version>\n\t</skin>\n\t<bannerLeft>\n\t\t<src>../images/nanohttpd_logo.png</src>\n\t</bannerLeft>\n\t<bannerRight>\n\t\t<src>../images/nanohttpd_logo_text.png</src>\n\t</bannerRight>\n\t<publishDate position=\"left\" format=\"yyyy-MM-dd\" />\n\t<version position=\"right\" />\n\t<poweredBy>\n\t\t<logo name=\"Maven\" href=\"http://maven.apache.org/\"\n\t\t\timg=\"http://maven.apache.org/images/logos/maven-feather.png\" />\n\t</poweredBy>\n\t<custom>\n\t\t<fluidoSkin>\n\t\t\t<topBarEnabled>false</topBarEnabled>\n\t\t\t<sideBarEnabled>true</sideBarEnabled>\n\t\t\t<gitHub>\n\t\t\t\t<projectId>Nanohttpd/nanohttpd</projectId>\n\t\t\t\t<ribbonOrientation>right</ribbonOrientation>\n\t\t\t\t<ribbonColor>black</ribbonColor>\n\t\t\t</gitHub>\n\t\t</fluidoSkin>\n\t</custom>\n\t<body>\n\t\t<breadcrumbs>\n\t\t\t<item name=\"${project.name}\" href=\"index.html\" />\n\t\t</breadcrumbs>\n\t\t<menu name=\"Documentation\">\n\t\t\t<item name=\"About\" href=\"index.html\" />\n\t\t</menu>\n\t\t<menu ref=\"modules\" />\n\t\t<menu ref=\"reports\" />\n\t</body>\n</project>"
  },
  {
    "path": "core/src/test/java/org/nanohttpd/junit/protocols/http/BadRequestTest.java",
    "content": "package org.nanohttpd.junit.protocols.http;\n\n/*\n * #%L\n * NanoHttpd-Core\n * %%\n * Copyright (C) 2012 - 2016 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\n\nimport org.junit.Test;\n\npublic class BadRequestTest extends HttpServerTest {\n\n    @Test\n    public void testEmptyRequest() throws IOException {\n        ByteArrayOutputStream outputStream = invokeServer(\"\\n\\n\");\n        String[] expected = new String[]{\n            \"HTTP/1.1 400 Bad Request\"\n        };\n        assertResponse(outputStream, expected);\n    }\n\n    @Test\n    public void testInvalidMethod() throws IOException {\n        ByteArrayOutputStream outputStream = invokeServer(\"GETT http://example.com\");\n        String[] expected = new String[]{\n            \"HTTP/1.1 400 Bad Request\"\n        };\n        assertResponse(outputStream, expected);\n    }\n\n    @Test\n    public void testMissingURI() throws IOException {\n        ByteArrayOutputStream outputStream = invokeServer(\"GET\");\n        String[] expected = new String[]{\n            \"HTTP/1.1 400 Bad Request\"\n        };\n        assertResponse(outputStream, expected);\n    }\n\n}\n"
  },
  {
    "path": "core/src/test/java/org/nanohttpd/junit/protocols/http/CookieHandlerTest.java",
    "content": "package org.nanohttpd.junit.protocols.http;\n\n/*\n * #%L\n * NanoHttpd-Core\n * %%\n * Copyright (C) 2012 - 2016 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertTrue;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.text.ParseException;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\nimport java.util.HashSet;\nimport java.util.Locale;\nimport java.util.Set;\nimport java.util.TimeZone;\n\nimport org.junit.Test;\nimport org.nanohttpd.protocols.http.HTTPSession;\nimport org.nanohttpd.protocols.http.content.CookieHandler;\nimport org.nanohttpd.protocols.http.response.Response;\n\npublic class CookieHandlerTest extends HttpServerTest {\n\n    @Test\n    public void testCookieHeaderCorrectlyParsed() throws IOException {\n        StringBuilder requestBuilder = new StringBuilder();\n        requestBuilder.append(\"GET \" + HttpServerTest.URI + \" HTTP/1.1\").append(System.getProperty(\"line.separator\")).append(\"Cookie: theme=light; sessionToken=abc123\");\n\n        ByteArrayInputStream inputStream = new ByteArrayInputStream(requestBuilder.toString().getBytes());\n        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();\n        HTTPSession session = this.testServer.createSession(this.tempFileManager, inputStream, outputStream);\n        session.execute();\n        Set<String> allCookies = new HashSet<String>();\n        CookieHandler cookieHandler = session.getCookies();\n        for (String cookie : cookieHandler) {\n            allCookies.add(cookie);\n        }\n        assertTrue(\"cookie specified in header not correctly parsed\", allCookies.contains(\"theme\"));\n        assertTrue(\"cookie specified in header not correctly parsed\", allCookies.contains(\"sessionToken\"));\n        assertEquals(\"cookie value not correctly parsed\", \"light\", cookieHandler.read(\"theme\"));\n        assertEquals(\"cookie value not correctly parsed\", \"abc123\", cookieHandler.read(\"sessionToken\"));\n\n    }\n\n    @Test\n    public void testCookieHeaderWithSpecialCharactersCorrectlyParsed() throws IOException {\n        StringBuilder requestBuilder = new StringBuilder();\n        // not including ; = and ,\n        requestBuilder.append(\"GET \" + HttpServerTest.URI + \" HTTP/1.1\").append(System.getProperty(\"line.separator\"))\n                .append(\"Cookie: theme=light; sessionToken=abc123!@#$%^&*()-_+{}[]\\\\|:\\\"'<>.?/\");\n\n        ByteArrayInputStream inputStream = new ByteArrayInputStream(requestBuilder.toString().getBytes());\n        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();\n        HTTPSession session = this.testServer.createSession(this.tempFileManager, inputStream, outputStream);\n        session.execute();\n        Set<String> allCookies = new HashSet<String>();\n        CookieHandler cookieHandler = session.getCookies();\n        for (String cookie : cookieHandler) {\n            allCookies.add(cookie);\n        }\n        assertTrue(\"cookie specified in header not correctly parsed\", allCookies.contains(\"theme\"));\n        assertTrue(\"cookie specified in header not correctly parsed\", allCookies.contains(\"sessionToken\"));\n        assertEquals(\"cookie value not correctly parsed\", \"light\", cookieHandler.read(\"theme\"));\n        assertEquals(\"cookie value not correctly parsed\", \"abc123!@#$%^&*()-_+{}[]\\\\|:\\\"'<>.?/\", cookieHandler.read(\"sessionToken\"));\n\n    }\n\n    @Test\n    public void testUnloadQueue() throws IOException {\n        StringBuilder requestBuilder = new StringBuilder();\n        requestBuilder.append(\"GET \" + HttpServerTest.URI + \" HTTP/1.1\").append(System.getProperty(\"line.separator\")).append(\"Cookie: theme=light; sessionToken=abc123\");\n\n        ByteArrayInputStream inputStream = new ByteArrayInputStream(requestBuilder.toString().getBytes());\n        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();\n        HTTPSession session = this.testServer.createSession(this.tempFileManager, inputStream, outputStream);\n        session.execute();\n        CookieHandler cookieHandler = session.getCookies();\n        Response response = Response.newFixedLengthResponse(\"\");\n        cookieHandler.set(\"name\", \"value\", 30);\n        cookieHandler.unloadQueue(response);\n        String setCookieHeader = response.getCookieHeaders().get(0);\n        assertTrue(\"unloadQueue did not set the cookies correctly\", setCookieHeader.startsWith(\"name=value; expires=\"));\n    }\n\n    @Test\n    public void testDelete() throws IOException, ParseException {\n        StringBuilder requestBuilder = new StringBuilder();\n        requestBuilder.append(\"GET \" + HttpServerTest.URI + \" HTTP/1.1\").append(System.getProperty(\"line.separator\")).append(\"Cookie: theme=light; sessionToken=abc123\");\n\n        ByteArrayInputStream inputStream = new ByteArrayInputStream(requestBuilder.toString().getBytes());\n        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();\n        HTTPSession session = this.testServer.createSession(this.tempFileManager, inputStream, outputStream);\n        session.execute();\n        CookieHandler cookieHandler = session.getCookies();\n\n        Response response = Response.newFixedLengthResponse(\"\");\n        cookieHandler.delete(\"name\");\n        cookieHandler.unloadQueue(response);\n\n        String setCookieHeader = response.getCookieHeaders().get(0);\n        SimpleDateFormat dateFormat = new SimpleDateFormat(\"EEE, dd MMM yyyy HH:mm:ss z\", Locale.US);\n        dateFormat.setTimeZone(TimeZone.getTimeZone(\"GMT\"));\n        String dateString = setCookieHeader.split(\";\")[1].split(\"=\")[1].trim();\n        Date date = dateFormat.parse(dateString);\n        assertTrue(\"Deleted cookie's expiry time should be a time in the past\", date.compareTo(new Date()) < 0);\n    }\n}\n"
  },
  {
    "path": "core/src/test/java/org/nanohttpd/junit/protocols/http/CookieTest.java",
    "content": "package org.nanohttpd.junit.protocols.http;\n\n/*\n * #%L\n * NanoHttpd-Core\n * %%\n * Copyright (C) 2012 - 2016 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\nimport static org.junit.Assert.assertFalse;\nimport static org.junit.Assert.assertNotNull;\nimport static org.junit.Assert.assertTrue;\n\nimport java.util.Random;\n\nimport org.junit.Test;\nimport org.nanohttpd.protocols.http.content.Cookie;\n\npublic class CookieTest {\n\n    @Test\n    public void testGetHTTPTime() {\n        Random random = new Random();\n        int randomExpirationTime = random.nextInt(100);\n        assertNotNull(\"getHTTPTime should return a non-null value for \" + randomExpirationTime + \" days\", Cookie.getHTTPTime(randomExpirationTime));\n    }\n\n    @Test\n    public void testCookieWithNoExplicitExpirationTime() {\n        Cookie cookie = new Cookie(\"CookieKey\", \"CookieValue\");\n        assertTrue(\"Cookie header should contain cookie key\", cookie.getHTTPHeader().contains(\"CookieKey\"));\n        assertTrue(\"Cookie header should contain cookie value\", cookie.getHTTPHeader().contains(\"CookieValue\"));\n    }\n\n    @Test\n    public void testCookieWithExplicitExpirationTime() {\n        Cookie cookie = new Cookie(\"CookieKey\", \"CookieValue\", 40);\n        assertFalse(\"The default 30 days expires string should not be avaialbe in the cookie header\" + \" because the expiry has been specified as 40 days\", cookie\n                .getHTTPHeader().contains(Cookie.getHTTPTime(30)));\n        assertTrue(\"Cookie header should contain cookie key\", cookie.getHTTPHeader().contains(\"CookieKey\"));\n        assertTrue(\"Cookie header should contain cookie value\", cookie.getHTTPHeader().contains(\"CookieValue\"));\n    }\n\n    @Test\n    public void testCookieWithExpiresString() {\n        Random random = new Random();\n        int randomExpirationTime = random.nextInt(100);\n        String expiresString = Cookie.getHTTPTime(randomExpirationTime);\n        Cookie cookie = new Cookie(\"CookieKey\", \"CookieValue\", expiresString);\n        assertTrue(\"Cookie should contain the expirs string passed in the constructor\", cookie.getHTTPHeader().contains(expiresString));\n        assertTrue(\"Cookie header should contain cookie key\", cookie.getHTTPHeader().contains(\"CookieKey\"));\n        assertTrue(\"Cookie header should contain cookie value\", cookie.getHTTPHeader().contains(\"CookieValue\"));\n    }\n\n}\n"
  },
  {
    "path": "core/src/test/java/org/nanohttpd/junit/protocols/http/HttpChunkedResponseTest.java",
    "content": "package org.nanohttpd.junit.protocols.http;\n\n/*\n * #%L\n * NanoHttpd-Core\n * %%\n * Copyright (C) 2012 - 2016 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.PipedInputStream;\n\nimport org.nanohttpd.protocols.http.response.Response;\nimport org.nanohttpd.protocols.http.response.Status;\n\npublic class HttpChunkedResponseTest extends HttpServerTest {\n\n    private static class ChunkedInputStream extends PipedInputStream {\n\n        int chunk = 0;\n\n        String[] chunks;\n\n        private ChunkedInputStream(String[] chunks) {\n            this.chunks = chunks;\n        }\n\n        @Override\n        public synchronized int read(byte[] buffer, int off, int len) throws IOException {\n            // Too implementation-linked, but...\n            for (int i = 0; i < this.chunks[this.chunk].length(); ++i) {\n                buffer[i] = (byte) this.chunks[this.chunk].charAt(i);\n            }\n            return this.chunks[this.chunk++].length();\n        }\n    }\n\n    @org.junit.Test\n    public void thatChunkedContentIsChunked() throws Exception {\n        PipedInputStream pipedInputStream = new ChunkedInputStream(new String[]{\n            \"some\",\n            \"thing which is longer than sixteen characters\",\n            \"whee!\",\n            \"\"\n        });\n        String[] expected = {\n            \"HTTP/1.1 200 OK\",\n            \"Content-Type: what/ever\",\n            \"Date: .*\",\n            \"Connection: keep-alive\",\n            \"Transfer-Encoding: chunked\",\n            \"\",\n            \"4\",\n            \"some\",\n            \"2d\",\n            \"thing which is longer than sixteen characters\",\n            \"5\",\n            \"whee!\",\n            \"0\",\n            \"\"\n        };\n        this.testServer.response = Response.newChunkedResponse(Status.OK, \"what/ever\", pipedInputStream);\n        this.testServer.response.setChunkedTransfer(true);\n\n        ByteArrayOutputStream byteArrayOutputStream = invokeServer(\"GET / HTTP/1.1\");\n\n        assertResponse(byteArrayOutputStream, expected);\n    }\n}\n"
  },
  {
    "path": "core/src/test/java/org/nanohttpd/junit/protocols/http/HttpDeleteRequestTest.java",
    "content": "package org.nanohttpd.junit.protocols.http;\n\n/*\n * #%L\n * NanoHttpd-Core\n * %%\n * Copyright (C) 2012 - 2015 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.InputStream;\n\nimport org.junit.Test;\nimport org.nanohttpd.protocols.http.NanoHTTPD;\nimport org.nanohttpd.protocols.http.response.Response;\nimport org.nanohttpd.protocols.http.response.Status;\n\npublic class HttpDeleteRequestTest extends HttpServerTest {\n\n    @Test\n    public void testDeleteRequestThatDoesntSendBackResponseBody_EmptyString() throws Exception {\n        this.testServer.response = Response.newFixedLengthResponse(Status.NO_CONTENT, NanoHTTPD.MIME_HTML, \"\");\n\n        ByteArrayOutputStream outputStream = invokeServer(\"DELETE \" + HttpServerTest.URI + \" HTTP/1.1\");\n\n        String[] expected = {\n            \"HTTP/1.1 204 No Content\",\n            \"Content-Type: text/html\",\n            \"Date: .*\",\n            \"Connection: keep-alive\",\n            \"Content-Length: 0\",\n            \"\"\n        };\n\n        assertResponse(outputStream, expected);\n    }\n\n    @Test\n    public void testDeleteRequestThatDoesntSendBackResponseBody_NullInputStream() throws Exception {\n        this.testServer.response = Response.newChunkedResponse(Status.NO_CONTENT, NanoHTTPD.MIME_HTML, (InputStream) null);\n\n        ByteArrayOutputStream outputStream = invokeServer(\"DELETE \" + HttpServerTest.URI + \" HTTP/1.1\");\n\n        String[] expected = {\n            \"HTTP/1.1 204 No Content\",\n            \"Content-Type: text/html\",\n            \"Date: .*\",\n            \"Connection: keep-alive\",\n            \"Content-Length: 0\",\n            \"\"\n        };\n\n        assertResponse(outputStream, expected);\n    }\n\n    @Test\n    public void testDeleteRequestThatDoesntSendBackResponseBody_NullString() throws Exception {\n        this.testServer.response = Response.newFixedLengthResponse(Status.NO_CONTENT, NanoHTTPD.MIME_HTML, (String) null);\n\n        ByteArrayOutputStream outputStream = invokeServer(\"DELETE \" + HttpServerTest.URI + \" HTTP/1.1\");\n\n        String[] expected = {\n            \"HTTP/1.1 204 No Content\",\n            \"Content-Type: text/html\",\n            \"Date: .*\",\n            \"Connection: keep-alive\",\n            \"Content-Length: 0\",\n            \"\"\n        };\n\n        assertResponse(outputStream, expected);\n    }\n\n    @Test\n    public void testDeleteRequestThatSendsBackResponseBody_Accepted() throws Exception {\n        this.testServer.response = Response.newFixedLengthResponse(Status.ACCEPTED, \"application/xml\", \"<body />\");\n\n        ByteArrayOutputStream outputStream = invokeServer(\"DELETE \" + HttpServerTest.URI + \" HTTP/1.1\");\n\n        String[] expected = {\n            \"HTTP/1.1 202 Accepted\",\n            \"Content-Type: application/xml\",\n            \"Date: .*\",\n            \"Connection: keep-alive\",\n            \"Content-Length: 8\",\n            \"\",\n            \"<body />\"\n        };\n\n        assertResponse(outputStream, expected);\n    }\n\n    @Test\n    public void testDeleteRequestThatSendsBackResponseBody_Success() throws Exception {\n        this.testServer.response = Response.newFixedLengthResponse(Status.OK, \"application/xml\", \"<body />\");\n\n        ByteArrayOutputStream outputStream = invokeServer(\"DELETE \" + HttpServerTest.URI + \" HTTP/1.1\");\n\n        String[] expected = {\n            \"HTTP/1.1 200 OK\",\n            \"Content-Type: application/xml\",\n            \"Date: .*\",\n            \"Connection: keep-alive\",\n            \"Content-Length: 8\",\n            \"\",\n            \"<body />\"\n        };\n\n        assertResponse(outputStream, expected);\n    }\n}\n"
  },
  {
    "path": "core/src/test/java/org/nanohttpd/junit/protocols/http/HttpGetRequestTest.java",
    "content": "package org.nanohttpd.junit.protocols.http;\n\n/*\n * #%L\n * NanoHttpd-Core\n * %%\n * Copyright (C) 2012 - 2015 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport static org.junit.Assert.assertArrayEquals;\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNotNull;\nimport static org.junit.Assert.assertTrue;\n\nimport java.io.ByteArrayOutputStream;\nimport java.util.List;\n\nimport org.junit.Test;\nimport org.nanohttpd.protocols.http.request.Method;\nimport org.nanohttpd.protocols.http.response.Response;\n\npublic class HttpGetRequestTest extends HttpServerTest {\n\n    @Test\n    public void testDecodingFieldWithEmptyValueAndFieldWithMissingValueGiveDifferentResults() {\n        invokeServer(\"GET \" + HttpServerTest.URI + \"?foo&bar= HTTP/1.1\");\n        assertTrue(this.testServer.decodedParamters.get(\"foo\") instanceof List);\n        assertEquals(0, this.testServer.decodedParamters.get(\"foo\").size());\n        assertTrue(this.testServer.decodedParamters.get(\"bar\") instanceof List);\n        assertEquals(1, this.testServer.decodedParamters.get(\"bar\").size());\n        assertEquals(\"\", this.testServer.decodedParamters.get(\"bar\").get(0));\n    }\n\n    @Test\n    public void testDecodingMixtureOfParameters() {\n        invokeServer(\"GET \" + HttpServerTest.URI + \"?foo=bar&foo=baz&zot&zim= HTTP/1.1\");\n        assertTrue(this.testServer.decodedParamters.get(\"foo\") instanceof List);\n        assertEquals(2, this.testServer.decodedParamters.get(\"foo\").size());\n        assertEquals(\"bar\", this.testServer.decodedParamters.get(\"foo\").get(0));\n        assertEquals(\"baz\", this.testServer.decodedParamters.get(\"foo\").get(1));\n        assertTrue(this.testServer.decodedParamters.get(\"zot\") instanceof List);\n        assertEquals(0, this.testServer.decodedParamters.get(\"zot\").size());\n        assertTrue(this.testServer.decodedParamters.get(\"zim\") instanceof List);\n        assertEquals(1, this.testServer.decodedParamters.get(\"zim\").size());\n        assertEquals(\"\", this.testServer.decodedParamters.get(\"zim\").get(0));\n    }\n\n    @Test\n    public void testDecodingParametersFromParameterMap() {\n        invokeServer(\"GET \" + HttpServerTest.URI + \"?foo=bar&foo=baz&zot&zim= HTTP/1.1\");\n        assertEquals(this.testServer.decodedParamters, this.testServer.decodedParamtersFromParameter);\n    }\n\n    // --------------------------------------------------------------------------------------------------------\n    // //\n\n    @Test\n    public void testDecodingParametersWithSingleValue() {\n        invokeServer(\"GET \" + HttpServerTest.URI + \"?foo=bar&baz=zot HTTP/1.1\");\n        assertEquals(\"foo=bar&baz=zot\", this.testServer.queryParameterString);\n        assertTrue(this.testServer.decodedParamters.get(\"foo\") instanceof List);\n        assertEquals(1, this.testServer.decodedParamters.get(\"foo\").size());\n        assertEquals(\"bar\", this.testServer.decodedParamters.get(\"foo\").get(0));\n        assertTrue(this.testServer.decodedParamters.get(\"baz\") instanceof List);\n        assertEquals(1, this.testServer.decodedParamters.get(\"baz\").size());\n        assertEquals(\"zot\", this.testServer.decodedParamters.get(\"baz\").get(0));\n    }\n\n    @Test\n    public void testDecodingParametersWithSingleValueAndMissingValue() {\n        invokeServer(\"GET \" + HttpServerTest.URI + \"?foo&baz=zot HTTP/1.1\");\n        assertEquals(\"foo&baz=zot\", this.testServer.queryParameterString);\n        assertTrue(this.testServer.decodedParamters.get(\"foo\") instanceof List);\n        assertEquals(0, this.testServer.decodedParamters.get(\"foo\").size());\n        assertTrue(this.testServer.decodedParamters.get(\"baz\") instanceof List);\n        assertEquals(1, this.testServer.decodedParamters.get(\"baz\").size());\n        assertEquals(\"zot\", this.testServer.decodedParamters.get(\"baz\").get(0));\n    }\n\n    @Test\n    public void testDecodingSingleFieldRepeated() {\n        invokeServer(\"GET \" + HttpServerTest.URI + \"?foo=bar&foo=baz HTTP/1.1\");\n        assertTrue(this.testServer.decodedParamters.get(\"foo\") instanceof List);\n        assertEquals(2, this.testServer.decodedParamters.get(\"foo\").size());\n        assertEquals(\"bar\", this.testServer.decodedParamters.get(\"foo\").get(0));\n        assertEquals(\"baz\", this.testServer.decodedParamters.get(\"foo\").get(1));\n    }\n\n    @Test\n    public void testEmptyHeadersSuppliedToServeMethodFromSimpleWorkingGetRequest() {\n        invokeServer(\"GET \" + HttpServerTest.URI + \" HTTP/1.1\");\n        assertNotNull(this.testServer.parms);\n        assertNotNull(this.testServer.parameters);\n        assertNotNull(this.testServer.header);\n        assertNotNull(this.testServer.files);\n        assertNotNull(this.testServer.uri);\n    }\n\n    @Test\n    public void testFullyQualifiedWorkingGetRequest() throws Exception {\n        ByteArrayOutputStream outputStream = invokeServer(\"GET \" + HttpServerTest.URI + \" HTTP/1.1\");\n\n        String[] expected = {\n            \"HTTP/1.1 200 OK\",\n            \"Content-Type: text/html\",\n            \"Date: .*\",\n            \"Connection: keep-alive\",\n            \"Content-Length: 0\",\n            \"\"\n        };\n\n        assertResponse(outputStream, expected);\n    }\n\n    @Test\n    public void testMultipleGetParameters() {\n        invokeServer(\"GET \" + HttpServerTest.URI + \"?foo=bar&baz=zot HTTP/1.1\");\n        assertEquals(\"bar\", this.testServer.parms.get(\"foo\"));\n        assertEquals(\"zot\", this.testServer.parms.get(\"baz\"));\n        assertEquals(\"bar\", this.testServer.parameters.get(\"foo\").get(0));\n        assertEquals(\"zot\", this.testServer.parameters.get(\"baz\").get(0));\n    }\n\n    @Test\n    public void testMultipleGetParametersWithMissingValue() {\n        invokeServer(\"GET \" + HttpServerTest.URI + \"?foo=&baz=zot HTTP/1.1\");\n        assertEquals(\"\", this.testServer.parms.get(\"foo\"));\n        assertEquals(\"zot\", this.testServer.parms.get(\"baz\"));\n        assertEquals(\"\", this.testServer.parameters.get(\"foo\").get(0));\n        assertEquals(\"zot\", this.testServer.parameters.get(\"baz\").get(0));\n    }\n\n    @Test\n    public void testMultipleGetParametersWithMissingValueAndRequestHeaders() {\n        invokeServer(\"GET \" + HttpServerTest.URI + \"?foo=&baz=zot HTTP/1.1\\nAccept: text/html\");\n        assertEquals(\"\", this.testServer.parms.get(\"foo\"));\n        assertEquals(\"zot\", this.testServer.parms.get(\"baz\"));\n        assertEquals(\"\", this.testServer.parameters.get(\"foo\").get(0));\n        assertEquals(\"zot\", this.testServer.parameters.get(\"baz\").get(0));\n        assertEquals(\"text/html\", this.testServer.header.get(\"accept\"));\n    }\n\n    @Test\n    public void testMultipleHeaderSuppliedToServeMethodFromSimpleWorkingGetRequest() {\n        String userAgent = \"jUnit 4.8.2 Unit Test\";\n        String accept = \"text/html\";\n        invokeServer(\"GET \" + HttpServerTest.URI + \" HTTP/1.1\\nUser-Agent: \" + userAgent + \"\\nAccept: \" + accept);\n        assertEquals(userAgent, this.testServer.header.get(\"user-agent\"));\n        assertEquals(accept, this.testServer.header.get(\"accept\"));\n    }\n\n    @Test\n    public void testOutputOfServeSentBackToClient() throws Exception {\n        String responseBody = \"Success!\";\n        this.testServer.response = Response.newFixedLengthResponse(responseBody);\n        ByteArrayOutputStream outputStream = invokeServer(\"GET \" + HttpServerTest.URI + \" HTTP/1.1\");\n\n        String[] expected = {\n            \"HTTP/1.1 200 OK\",\n            \"Content-Type: text/html\",\n            \"Date: .*\",\n            \"Connection: keep-alive\",\n            \"Content-Length: 8\",\n            \"\",\n            responseBody\n        };\n\n        assertResponse(outputStream, expected);\n    }\n\n    @Test\n    public void testSingleGetParameter() {\n        invokeServer(\"GET \" + HttpServerTest.URI + \"?foo=bar HTTP/1.1\");\n        assertEquals(\"bar\", this.testServer.parms.get(\"foo\"));\n        assertEquals(\"bar\", this.testServer.parameters.get(\"foo\").get(0));\n    }\n\n    @Test\n    public void testMultipleValueGetParameter() {\n        invokeServer(\"GET \" + HttpServerTest.URI + \"?foo=bar&foo=baz HTTP/1.1\");\n        assertEquals(\"bar\", this.testServer.parms.get(\"foo\"));\n        assertEquals(2, this.testServer.parameters.get(\"foo\").size());\n        assertEquals(\"bar\", this.testServer.parameters.get(\"foo\").get(0));\n        assertEquals(\"baz\", this.testServer.parameters.get(\"foo\").get(1));\n    }\n\n    @Test\n    public void testSingleGetParameterWithNoValue() {\n        invokeServer(\"GET \" + HttpServerTest.URI + \"?foo HTTP/1.1\");\n        assertEquals(\"\", this.testServer.parms.get(\"foo\"));\n        assertEquals(\"\", this.testServer.parameters.get(\"foo\").get(0));\n    }\n\n    @Test\n    public void testSingleUserAgentHeaderSuppliedToServeMethodFromSimpleWorkingGetRequest() {\n        String userAgent = \"jUnit 4.8.2 Unit Test\";\n        invokeServer(\"GET \" + HttpServerTest.URI + \" HTTP/1.1\\nUser-Agent: \" + userAgent + \"\\n\");\n        assertEquals(userAgent, this.testServer.header.get(\"user-agent\"));\n        assertEquals(Method.GET, this.testServer.method);\n        assertEquals(HttpServerTest.URI, this.testServer.uri);\n    }\n\n    @Test\n    public void testGetQueryParameterContainsSpace() {\n        invokeServer(\"GET \" + HttpServerTest.URI + \"?foo=bar%20baz HTTP/1.1\");\n        assertEquals(\"Parameter count in URL and decodedParameters should match.\", 1, this.testServer.decodedParamters.size());\n        assertEquals(\"The query parameter value with space decoding incorrect\", \"bar baz\", this.testServer.decodedParamters.get(\"foo\").get(0));\n    }\n\n    @Test\n    public void testGetQueryParameterContainsQuestionMark() {\n        invokeServer(\"GET \" + HttpServerTest.URI + \"?foo=bar%3F HTTP/1.1\");\n        assertEquals(\"Parameter count in URL and decodedParameters should match.\", 1, this.testServer.decodedParamters.size());\n        assertEquals(\"The query parameter value with question mark decoding incorrect\", \"bar?\", this.testServer.decodedParamters.get(\"foo\").get(0));\n    }\n\n    @Test\n    public void testGetQueryParameterContainsAmpersand() {\n        invokeServer(\"GET \" + HttpServerTest.URI + \"?foo=bar%26 HTTP/1.1\");\n        assertEquals(\"Parameter count in URL and decodedParameters should match.\", 1, this.testServer.decodedParamters.size());\n        assertEquals(\"The query parameter value with ampersand decoding incorrect\", \"bar&\", this.testServer.decodedParamters.get(\"foo\").get(0));\n    }\n\n    @Test\n    public void testGetQueryParameterContainsSpecialCharactersSingleFieldRepeated() {\n        invokeServer(\"GET \" + HttpServerTest.URI + \"?foo=bar%20baz&foo=bar%3F&foo=bar%26 HTTP/1.1\");\n        assertEquals(\"Parameter count in URL and decodedParameters should match.\", 1, this.testServer.decodedParamters.size());\n        String[] parametersAsArray = this.testServer.decodedParamters.get(\"foo\").toArray(new String[0]);\n        String[] expected = new String[]{\n            \"bar baz\",\n            \"bar?\",\n            \"bar&\"\n        };\n        assertArrayEquals(\"Repeated parameter not decoded correctly\", expected, parametersAsArray);\n    }\n}\n"
  },
  {
    "path": "core/src/test/java/org/nanohttpd/junit/protocols/http/HttpHeadRequestTest.java",
    "content": "package org.nanohttpd.junit.protocols.http;\n\n/*\n * #%L\n * NanoHttpd-Core\n * %%\n * Copyright (C) 2012 - 2015 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport static junit.framework.Assert.assertEquals;\nimport static junit.framework.Assert.assertNotNull;\nimport static junit.framework.Assert.assertTrue;\n\nimport java.io.ByteArrayOutputStream;\nimport java.util.List;\n\nimport org.junit.Test;\nimport org.nanohttpd.protocols.http.request.Method;\nimport org.nanohttpd.protocols.http.response.Response;\n\npublic class HttpHeadRequestTest extends HttpServerTest {\n\n    @Override\n    public void setUp() throws Exception {\n        super.setUp();\n        String responseBody = \"Success!\";\n        this.testServer.response = Response.newFixedLengthResponse(responseBody);\n    }\n\n    @Test\n    public void testDecodingFieldWithEmptyValueAndFieldWithMissingValueGiveDifferentResults() {\n        invokeServer(\"HEAD \" + HttpServerTest.URI + \"?foo&bar= HTTP/1.1\");\n        assertTrue(this.testServer.decodedParamters.get(\"foo\") instanceof List);\n        assertEquals(0, this.testServer.decodedParamters.get(\"foo\").size());\n        assertTrue(this.testServer.decodedParamters.get(\"bar\") instanceof List);\n        assertEquals(1, this.testServer.decodedParamters.get(\"bar\").size());\n        assertEquals(\"\", this.testServer.decodedParamters.get(\"bar\").get(0));\n    }\n\n    @Test\n    public void testDecodingMixtureOfParameters() {\n        invokeServer(\"HEAD \" + HttpServerTest.URI + \"?foo=bar&foo=baz&zot&zim= HTTP/1.1\");\n        assertTrue(this.testServer.decodedParamters.get(\"foo\") instanceof List);\n        assertEquals(2, this.testServer.decodedParamters.get(\"foo\").size());\n        assertEquals(\"bar\", this.testServer.decodedParamters.get(\"foo\").get(0));\n        assertEquals(\"baz\", this.testServer.decodedParamters.get(\"foo\").get(1));\n        assertTrue(this.testServer.decodedParamters.get(\"zot\") instanceof List);\n        assertEquals(0, this.testServer.decodedParamters.get(\"zot\").size());\n        assertTrue(this.testServer.decodedParamters.get(\"zim\") instanceof List);\n        assertEquals(1, this.testServer.decodedParamters.get(\"zim\").size());\n        assertEquals(\"\", this.testServer.decodedParamters.get(\"zim\").get(0));\n    }\n\n    @Test\n    public void testDecodingParametersFromParameterMap() {\n        invokeServer(\"HEAD \" + HttpServerTest.URI + \"?foo=bar&foo=baz&zot&zim= HTTP/1.1\");\n        assertEquals(this.testServer.decodedParamters, this.testServer.decodedParamtersFromParameter);\n    }\n\n    // --------------------------------------------------------------------------------------------------------\n    // //\n\n    @Test\n    public void testDecodingParametersWithSingleValue() {\n        invokeServer(\"HEAD \" + HttpServerTest.URI + \"?foo=bar&baz=zot HTTP/1.1\");\n        assertEquals(\"foo=bar&baz=zot\", this.testServer.queryParameterString);\n        assertTrue(this.testServer.decodedParamters.get(\"foo\") instanceof List);\n        assertEquals(1, this.testServer.decodedParamters.get(\"foo\").size());\n        assertEquals(\"bar\", this.testServer.decodedParamters.get(\"foo\").get(0));\n        assertTrue(this.testServer.decodedParamters.get(\"baz\") instanceof List);\n        assertEquals(1, this.testServer.decodedParamters.get(\"baz\").size());\n        assertEquals(\"zot\", this.testServer.decodedParamters.get(\"baz\").get(0));\n    }\n\n    @Test\n    public void testDecodingParametersWithSingleValueAndMissingValue() {\n        invokeServer(\"HEAD \" + HttpServerTest.URI + \"?foo&baz=zot HTTP/1.1\");\n        assertEquals(\"foo&baz=zot\", this.testServer.queryParameterString);\n        assertTrue(this.testServer.decodedParamters.get(\"foo\") instanceof List);\n        assertEquals(0, this.testServer.decodedParamters.get(\"foo\").size());\n        assertTrue(this.testServer.decodedParamters.get(\"baz\") instanceof List);\n        assertEquals(1, this.testServer.decodedParamters.get(\"baz\").size());\n        assertEquals(\"zot\", this.testServer.decodedParamters.get(\"baz\").get(0));\n    }\n\n    @Test\n    public void testDecodingSingleFieldRepeated() {\n        invokeServer(\"HEAD \" + HttpServerTest.URI + \"?foo=bar&foo=baz HTTP/1.1\");\n        assertTrue(this.testServer.decodedParamters.get(\"foo\") instanceof List);\n        assertEquals(2, this.testServer.decodedParamters.get(\"foo\").size());\n        assertEquals(\"bar\", this.testServer.decodedParamters.get(\"foo\").get(0));\n        assertEquals(\"baz\", this.testServer.decodedParamters.get(\"foo\").get(1));\n    }\n\n    @Test\n    public void testEmptyHeadersSuppliedToServeMethodFromSimpleWorkingGetRequest() {\n        invokeServer(\"HEAD \" + HttpServerTest.URI + \" HTTP/1.1\");\n        assertNotNull(this.testServer.parms);\n        assertNotNull(this.testServer.parameters);\n        assertNotNull(this.testServer.header);\n        assertNotNull(this.testServer.files);\n        assertNotNull(this.testServer.uri);\n    }\n\n    @Test\n    public void testHeadRequestDoesntSendBackResponseBody() throws Exception {\n        ByteArrayOutputStream outputStream = invokeServer(\"HEAD \" + HttpServerTest.URI + \" HTTP/1.1\");\n\n        String[] expected = {\n            \"HTTP/1.1 200 OK\",\n            \"Content-Type: text/html\",\n            \"Date: .*\",\n            \"Connection: keep-alive\",\n            \"Content-Length: 8\",\n            \"\"\n        };\n\n        assertResponse(outputStream, expected);\n    }\n\n    @Test\n    public void testMultipleGetParameters() {\n        invokeServer(\"HEAD \" + HttpServerTest.URI + \"?foo=bar&baz=zot HTTP/1.1\");\n        assertEquals(\"bar\", this.testServer.parms.get(\"foo\"));\n        assertEquals(\"zot\", this.testServer.parms.get(\"baz\"));\n        assertEquals(\"bar\", this.testServer.parameters.get(\"foo\").get(0));\n        assertEquals(\"zot\", this.testServer.parameters.get(\"baz\").get(0));\n    }\n\n    @Test\n    public void testMultipleGetParametersWithMissingValue() {\n        invokeServer(\"HEAD \" + HttpServerTest.URI + \"?foo=&baz=zot HTTP/1.1\");\n        assertEquals(\"\", this.testServer.parms.get(\"foo\"));\n        assertEquals(\"zot\", this.testServer.parms.get(\"baz\"));\n        assertEquals(\"\", this.testServer.parameters.get(\"foo\").get(0));\n        assertEquals(\"zot\", this.testServer.parameters.get(\"baz\").get(0));\n    }\n\n    @Test\n    public void testMultipleGetParametersWithMissingValueAndRequestHeaders() {\n        invokeServer(\"HEAD \" + HttpServerTest.URI + \"?foo=&baz=zot HTTP/1.1\\nAccept: text/html\");\n        assertEquals(\"\", this.testServer.parms.get(\"foo\"));\n        assertEquals(\"zot\", this.testServer.parms.get(\"baz\"));\n        assertEquals(\"\", this.testServer.parameters.get(\"foo\").get(0));\n        assertEquals(\"zot\", this.testServer.parameters.get(\"baz\").get(0));\n        assertEquals(\"text/html\", this.testServer.header.get(\"accept\"));\n    }\n\n    @Test\n    public void testMultipleHeaderSuppliedToServeMethodFromSimpleWorkingGetRequest() {\n        String userAgent = \"jUnit 4.8.2 Unit Test\";\n        String accept = \"text/html\";\n        invokeServer(\"HEAD \" + HttpServerTest.URI + \" HTTP/1.1\\nUser-Agent: \" + userAgent + \"\\nAccept: \" + accept);\n        assertEquals(userAgent, this.testServer.header.get(\"user-agent\"));\n        assertEquals(accept, this.testServer.header.get(\"accept\"));\n    }\n\n    @Test\n    public void testSingleGetParameter() {\n        invokeServer(\"HEAD \" + HttpServerTest.URI + \"?foo=bar HTTP/1.1\");\n        assertEquals(\"bar\", this.testServer.parms.get(\"foo\"));\n        assertEquals(\"bar\", this.testServer.parameters.get(\"foo\").get(0));\n    }\n\n    @Test\n    public void testMultipleValueGetParameter() {\n        invokeServer(\"HEAD \" + HttpServerTest.URI + \"?foo=bar&foo=baz HTTP/1.1\");\n        assertEquals(\"bar\", this.testServer.parms.get(\"foo\"));\n        assertEquals(2, this.testServer.parameters.get(\"foo\").size());\n        assertEquals(\"bar\", this.testServer.parameters.get(\"foo\").get(0));\n        assertEquals(\"baz\", this.testServer.parameters.get(\"foo\").get(1));\n    }\n\n    @Test\n    public void testSingleGetParameterWithNoValue() {\n        invokeServer(\"HEAD \" + HttpServerTest.URI + \"?foo HTTP/1.1\");\n        assertEquals(\"\", this.testServer.parms.get(\"foo\"));\n        assertEquals(\"\", this.testServer.parameters.get(\"foo\").get(0));\n    }\n\n    @Test\n    public void testSingleUserAgentHeaderSuppliedToServeMethodFromSimpleWorkingGetRequest() {\n        String userAgent = \"jUnit 4.8.2 Unit Test\";\n        invokeServer(\"HEAD \" + HttpServerTest.URI + \" HTTP/1.1\\nUser-Agent: \" + userAgent + \"\\n\");\n        assertEquals(userAgent, this.testServer.header.get(\"user-agent\"));\n        assertEquals(Method.HEAD, this.testServer.method);\n        assertEquals(HttpServerTest.URI, this.testServer.uri);\n    }\n\n}\n"
  },
  {
    "path": "core/src/test/java/org/nanohttpd/junit/protocols/http/HttpKeepAliveTest.java",
    "content": "package org.nanohttpd.junit.protocols.http;\n\n/*\n * #%L\n * NanoHttpd-Core\n * %%\n * Copyright (C) 2012 - 2015 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport static junit.framework.Assert.fail;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.PipedInputStream;\nimport java.io.PipedOutputStream;\n\nimport org.junit.Test;\nimport org.nanohttpd.protocols.http.HTTPSession;\nimport org.nanohttpd.protocols.http.tempfiles.DefaultTempFileManager;\n\npublic class HttpKeepAliveTest extends HttpServerTest {\n\n    private Throwable error = null;\n\n    @Test\n    public void testManyGetRequests() throws Exception {\n        String request = \"GET \" + HttpServerTest.URI + \" HTTP/1.1\\r\\n\\r\\n\";\n        String[] expected = {\n            \"HTTP/1.1 200 OK\",\n            \"Content-Type: text/html\",\n            \"Date: .*\",\n            \"Connection: keep-alive\",\n            \"Content-Length: 0\",\n            \"\"\n        };\n        testManyRequests(request, expected);\n    }\n\n    @Test\n    public void testManyPutRequests() throws Exception {\n        String data = \"BodyData 1\\nLine 2\";\n        String request = \"PUT \" + HttpServerTest.URI + \" HTTP/1.1\\r\\nContent-Length: \" + data.length() + \"\\r\\n\\r\\n\" + data;\n        String[] expected = {\n            \"HTTP/1.1 200 OK\",\n            \"Content-Type: text/html\",\n            \"Date: .*\",\n            \"Connection: keep-alive\",\n            \"Content-Length: 0\",\n            \"\"\n        };\n        testManyRequests(request, expected);\n    }\n\n    /**\n     * Issue the given request many times to check whether an error occurs. For\n     * this test, a small stack size is used, since a stack overflow is among\n     * the possible errors.\n     * \n     * @param request\n     *            The request to issue\n     * @param expected\n     *            The expected response\n     */\n    public void testManyRequests(final String request, final String[] expected) throws Exception {\n        Runnable r = new Runnable() {\n\n            @Override\n            public void run() {\n                try {\n                    PipedOutputStream requestStream = new PipedOutputStream();\n                    PipedInputStream inputStream = new PipedInputStream(requestStream);\n                    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();\n                    DefaultTempFileManager tempFileManager = new DefaultTempFileManager();\n                    try {\n                        HTTPSession session = HttpKeepAliveTest.this.testServer.createSession(tempFileManager, inputStream, outputStream);\n                        for (int i = 0; i < 2048; i++) {\n                            requestStream.write(request.getBytes());\n                            requestStream.flush();\n                            outputStream.reset();\n                            session.execute();\n                            assertResponse(outputStream, expected);\n                        }\n\n                        // Finally, try \"Connection: Close\"\n                        String closeReq = request.replaceAll(\"HTTP/1.1\", \"HTTP/1.1\\r\\nConnection: Close\");\n                        expected[3] = \"Connection: close\";\n                        requestStream.write(closeReq.getBytes());\n                        outputStream.reset();\n                        requestStream.flush();\n                        // Server should now close the socket by throwing a\n                        // SocketException:\n                        try {\n                            session.execute();\n                        } catch (java.net.SocketException se) {\n                            junit.framework.Assert.assertEquals(se.getMessage(), \"NanoHttpd Shutdown\");\n                        }\n                        assertResponse(outputStream, expected);\n\n                    } finally {\n                        tempFileManager.clear();\n                    }\n                } catch (Throwable t) {\n                    HttpKeepAliveTest.this.error = t;\n                }\n            }\n        };\n        Thread t = new Thread(null, r, \"Request Thread\", 1 << 17);\n        t.start();\n        t.join();\n        if (this.error != null) {\n            fail(\"\" + this.error);\n            this.error.printStackTrace();\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/test/java/org/nanohttpd/junit/protocols/http/HttpParsingTest.java",
    "content": "package org.nanohttpd.junit.protocols.http;\n\n/*\n * #%L\n * NanoHttpd-Core\n * %%\n * Copyright (C) 2012 - 2015 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport static junit.framework.Assert.assertEquals;\n\nimport org.junit.Test;\n\npublic class HttpParsingTest extends HttpServerTest {\n\n    @Test\n    public void testMultibyteCharacterSupport() throws Exception {\n        String expected = \"Chinese \\u738b Letters\";\n        String input = \"Chinese+%e7%8e%8b+Letters\";\n        assertEquals(expected, this.testServer.decodePercent(input));\n    }\n\n    @Test\n    public void testNormalCharacters() throws Exception {\n        for (int i = 0x20; i < 0x80; i++) {\n            String hex = Integer.toHexString(i);\n            String input = \"%\" + hex;\n            char expected = (char) i;\n            assertEquals(\"\" + expected, this.testServer.decodePercent(input));\n        }\n    }\n\n    @Test\n    public void testPlusInQueryParams() throws Exception {\n        assertEquals(\"foo bar\", this.testServer.decodePercent(\"foo+bar\"));\n    }\n}\n"
  },
  {
    "path": "core/src/test/java/org/nanohttpd/junit/protocols/http/HttpPostRequestTest.java",
    "content": "package org.nanohttpd.junit.protocols.http;\n\n/*\n * #%L\n * NanoHttpd-Core\n * %%\n * Copyright (C) 2012 - 2015 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport static org.junit.Assert.assertEquals;\n\nimport java.io.BufferedReader;\nimport java.io.FileReader;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.UUID;\n\nimport org.junit.Test;\n\npublic class HttpPostRequestTest extends HttpServerTest {\n\n    public static final String CONTENT_LENGTH = \"Content-Length: \";\n\n    public static final String FIELD = \"caption\";\n\n    public static final String VALUE = \"Summer vacation\";\n\n    public static final String FIELD2 = \"location\";\n\n    public static final String VALUE2 = \"Grand Canyon\";\n\n    public static final String POST_RAW_CONTENT_FILE_ENTRY = \"postData\";\n\n    public static final String VALUE_TEST_SIMPLE_RAW_DATA_WITH_AMPHASIS = \"Test raw data & Result value\";\n\n    /**\n     * contains common preparation steps for testing POST with Multipart Form\n     * \n     * @param fileName\n     *            Name of file to be uploaded\n     * @param fileContent\n     *            Content of file to be uploaded\n     * @return input String with POST request complete information including\n     *         header, length and content\n     */\n    private String preparePostWithMultipartForm(String fileName, String fileContent) {\n        String divider = UUID.randomUUID().toString();\n        String header = \"POST \" + HttpServerTest.URI + \" HTTP/1.1\\nContent-Type: \" + \"multipart/form-data, boundary=\" + divider + \"\\r\\n\";\n        String content =\n                \"--\" + divider + \"\\r\\n\" + \"Content-Disposition: form-data; name=\\\"\" + HttpPostRequestTest.FIELD + \"\\\"; filename=\\\"\" + fileName + \"\\\"\\r\\n\"\n                        + \"Content-Type: image/jpeg\\r\\n\" + \"\\r\\n\" + fileContent + \"\\r\\n\" + \"--\" + divider + \"--\\r\\n\";\n        int size = content.length() + header.length();\n        int contentLengthHeaderValueSize = String.valueOf(size).length();\n        int contentLength = size + contentLengthHeaderValueSize + HttpPostRequestTest.CONTENT_LENGTH.length();\n        String input = header + HttpPostRequestTest.CONTENT_LENGTH + (contentLength + 5) + \"\\r\\n\\r\\n\" + content;\n\n        return input;\n    }\n\n    @Test\n    public void testPostWithMultipartFormUpload() throws Exception {\n        String filename = \"GrandCanyon.txt\";\n        String fileContent = HttpPostRequestTest.VALUE;\n        String input = preparePostWithMultipartForm(filename, fileContent);\n\n        invokeServer(input);\n\n        assertEquals(1, this.testServer.parms.size());\n        assertEquals(1, this.testServer.parameters.size());\n        BufferedReader reader = new BufferedReader(new FileReader(this.testServer.files.get(HttpPostRequestTest.FIELD)));\n        List<String> lines = readLinesFromFile(reader);\n        assertLinesOfText(new String[]{\n            fileContent\n        }, lines);\n    }\n\n    @Test\n    public void testPostWithMultipartFormUploadFilenameHasSpaces() throws Exception {\n        String fileNameWithSpace = \"Grand Canyon.txt\";\n        String fileContent = HttpPostRequestTest.VALUE;\n        String input = preparePostWithMultipartForm(fileNameWithSpace, fileContent);\n\n        invokeServer(input);\n\n        String fileNameAfter = new ArrayList<String>(this.testServer.parms.values()).get(0);\n        assertEquals(fileNameWithSpace, fileNameAfter);\n\n        fileNameAfter = new ArrayList<String>(this.testServer.parameters.values().iterator().next()).get(0);\n        assertEquals(fileNameWithSpace, fileNameAfter);\n    }\n\n    @Test\n    public void testPostWithMultipleMultipartFormFields() throws Exception {\n        String divider = UUID.randomUUID().toString();\n        String header = \"POST \" + HttpServerTest.URI + \" HTTP/1.1\\nContent-Type: \" + \"multipart/form-data; boundary=\" + divider + \"\\n\";\n        String content =\n                \"--\" + divider + \"\\r\\n\" + \"Content-Disposition: form-data; name=\\\"\" + HttpPostRequestTest.FIELD + \"\\\"\\r\\n\" + \"\\r\\n\" + HttpPostRequestTest.VALUE + \"\\r\\n\"\n                        + \"--\" + divider + \"\\r\\n\" + \"Content-Disposition: form-data; name=\\\"\" + HttpPostRequestTest.FIELD2 + \"\\\"\\r\\n\" + \"\\r\\n\" + HttpPostRequestTest.VALUE2\n                        + \"\\r\\n\" + \"--\" + divider + \"--\\r\\n\";\n        int size = content.length() + header.length();\n        int contentLengthHeaderValueSize = String.valueOf(size).length();\n        int contentLength = size + contentLengthHeaderValueSize + HttpPostRequestTest.CONTENT_LENGTH.length();\n        String input = header + HttpPostRequestTest.CONTENT_LENGTH + (contentLength + 4) + \"\\r\\n\\r\\n\" + content;\n        invokeServer(input);\n\n        assertEquals(2, this.testServer.parms.size());\n        assertEquals(HttpPostRequestTest.VALUE, this.testServer.parms.get(HttpPostRequestTest.FIELD));\n        assertEquals(HttpPostRequestTest.VALUE2, this.testServer.parms.get(HttpPostRequestTest.FIELD2));\n\n        assertEquals(2, this.testServer.parameters.size());\n        assertEquals(HttpPostRequestTest.VALUE, this.testServer.parameters.get(HttpPostRequestTest.FIELD).get(0));\n        assertEquals(HttpPostRequestTest.VALUE2, this.testServer.parameters.get(HttpPostRequestTest.FIELD2).get(0));\n    }\n\n    @Test\n    public void testPostWithMultipleMultipartFormFieldsWhereContentTypeWasSeparatedByComma() throws Exception {\n        String divider = UUID.randomUUID().toString();\n        String header = \"POST \" + HttpServerTest.URI + \" HTTP/1.1\\nContent-Type: \" + \"multipart/form-data, boundary=\" + divider + \"\\r\\n\";\n        String content =\n                \"--\" + divider + \"\\r\\n\" + \"Content-Disposition: form-data; name=\\\"\" + HttpPostRequestTest.FIELD + \"\\\"\\r\\n\" + \"\\r\\n\" + HttpPostRequestTest.VALUE + \"\\r\\n\"\n                        + \"--\" + divider + \"\\r\\n\" + \"Content-Disposition: form-data; name=\\\"\" + HttpPostRequestTest.FIELD2 + \"\\\"\\r\\n\" + \"\\r\\n\" + HttpPostRequestTest.VALUE2\n                        + \"\\r\\n\" + \"--\" + divider + \"--\\r\\n\";\n        int size = content.length() + header.length();\n        int contentLengthHeaderValueSize = String.valueOf(size).length();\n        int contentLength = size + contentLengthHeaderValueSize + HttpPostRequestTest.CONTENT_LENGTH.length();\n        String input = header + HttpPostRequestTest.CONTENT_LENGTH + (contentLength + 4) + \"\\r\\n\\r\\n\" + content;\n        invokeServer(input);\n\n        assertEquals(2, this.testServer.parms.size());\n        assertEquals(HttpPostRequestTest.VALUE, this.testServer.parms.get(HttpPostRequestTest.FIELD));\n        assertEquals(HttpPostRequestTest.VALUE2, this.testServer.parms.get(HttpPostRequestTest.FIELD2));\n\n        assertEquals(2, this.testServer.parameters.size());\n        assertEquals(HttpPostRequestTest.VALUE, this.testServer.parameters.get(HttpPostRequestTest.FIELD).get(0));\n        assertEquals(HttpPostRequestTest.VALUE2, this.testServer.parameters.get(HttpPostRequestTest.FIELD2).get(0));\n    }\n\n    @Test\n    public void testSimplePostWithSingleMultipartFormField() throws Exception {\n        String divider = UUID.randomUUID().toString();\n        String header = \"POST \" + HttpServerTest.URI + \" HTTP/1.1\\nContent-Type: \" + \"multipart/form-data; boundary=\" + divider + \"\\r\\n\";\n        String content =\n                \"--\" + divider + \"\\r\\n\" + \"Content-Disposition: form-data; name=\\\"\" + HttpPostRequestTest.FIELD + \"\\\"\\r\\n\" + \"\\r\\n\" + HttpPostRequestTest.VALUE + \"\\r\\n\"\n                        + \"--\" + divider + \"--\\r\\n\";\n        int size = content.length() + header.length();\n        int contentLengthHeaderValueSize = String.valueOf(size).length();\n        int contentLength = size + contentLengthHeaderValueSize + HttpPostRequestTest.CONTENT_LENGTH.length();\n        String input = header + HttpPostRequestTest.CONTENT_LENGTH + (contentLength + 4) + \"\\r\\n\\r\\n\" + content;\n        invokeServer(input);\n\n        assertEquals(1, this.testServer.parms.size());\n        assertEquals(HttpPostRequestTest.VALUE, this.testServer.parms.get(HttpPostRequestTest.FIELD));\n\n        assertEquals(1, this.testServer.parameters.size());\n        assertEquals(HttpPostRequestTest.VALUE, this.testServer.parameters.get(HttpPostRequestTest.FIELD).get(0));\n    }\n\n    @Test\n    public void testSimpleRawPostData() throws Exception {\n        String header = \"POST \" + HttpServerTest.URI + \" HTTP/1.1\\n\";\n        String content = HttpPostRequestTest.VALUE_TEST_SIMPLE_RAW_DATA_WITH_AMPHASIS + \"\\r\\n\";\n        int size = content.length() + header.length();\n        int contentLengthHeaderValueSize = String.valueOf(size).length();\n        int contentLength = size + contentLengthHeaderValueSize + HttpPostRequestTest.CONTENT_LENGTH.length();\n        String input = header + HttpPostRequestTest.CONTENT_LENGTH + (contentLength + 4) + \"\\r\\n\\r\\n\" + content;\n        invokeServer(input);\n        assertEquals(0, this.testServer.parms.size());\n        assertEquals(0, this.testServer.parameters.size());\n        assertEquals(1, this.testServer.files.size());\n        assertEquals(HttpPostRequestTest.VALUE_TEST_SIMPLE_RAW_DATA_WITH_AMPHASIS, this.testServer.files.get(HttpPostRequestTest.POST_RAW_CONTENT_FILE_ENTRY));\n    }\n\n    @Test\n    public void testPostWithMultipartFormFieldsAndFile() throws IOException {\n        String fileName = \"GrandCanyon.txt\";\n        String fileContent = HttpPostRequestTest.VALUE;\n\n        String divider = UUID.randomUUID().toString();\n        String header = \"POST \" + HttpServerTest.URI + \" HTTP/1.1\\nContent-Type: \" + \"multipart/form-data; boundary=\" + divider + \"\\n\";\n        String content =\n                \"--\" + divider + \"\\r\\n\" + \"Content-Disposition: form-data; name=\\\"\" + HttpPostRequestTest.FIELD + \"\\\"; filename=\\\"\" + fileName + \"\\\"\\r\\n\"\n                        + \"Content-Type: image/jpeg\\r\\n\" + \"\\r\\n\" + fileContent + \"\\r\\n\" + \"--\" + divider + \"\\r\\n\" + \"Content-Disposition: form-data; name=\\\"\"\n                        + HttpPostRequestTest.FIELD2 + \"\\\"\\r\\n\" + \"\\r\\n\" + HttpPostRequestTest.VALUE2 + \"\\r\\n\" + \"--\" + divider + \"--\\r\\n\";\n        int size = content.length() + header.length();\n        int contentLengthHeaderValueSize = String.valueOf(size).length();\n        int contentLength = size + contentLengthHeaderValueSize + HttpPostRequestTest.CONTENT_LENGTH.length();\n        String input = header + HttpPostRequestTest.CONTENT_LENGTH + (contentLength + 4) + \"\\r\\n\\r\\n\" + content;\n        invokeServer(input);\n\n        assertEquals(\"Parms count did not match.\", 2, this.testServer.parms.size());\n        assertEquals(\"Parameters count did not match.\", 2, this.testServer.parameters.size());\n        assertEquals(\"Param value did not match\", HttpPostRequestTest.VALUE2, this.testServer.parms.get(HttpPostRequestTest.FIELD2));\n        assertEquals(\"Parameter value did not match\", HttpPostRequestTest.VALUE2, this.testServer.parameters.get(HttpPostRequestTest.FIELD2).get(0));\n        BufferedReader reader = new BufferedReader(new FileReader(this.testServer.files.get(HttpPostRequestTest.FIELD)));\n        List<String> lines = readLinesFromFile(reader);\n        assertLinesOfText(new String[]{\n            fileContent\n        }, lines);\n    }\n\n    @Test\n    public void testPostWithMultipartFormUploadMultipleFiles() throws IOException {\n\n        String fileName = \"GrandCanyon.txt\";\n        String fileContent = HttpPostRequestTest.VALUE;\n        String file2Name = \"AnotherPhoto.txt\";\n        String file2Content = HttpPostRequestTest.VALUE2;\n        String divider = UUID.randomUUID().toString();\n        String header = \"POST \" + HttpServerTest.URI + \" HTTP/1.1\\nContent-Type: \" + \"multipart/form-data; boundary=\" + divider + \"\\n\";\n        String content = \"--\" + divider + \"\\r\\n\"//\n                + \"Content-Disposition: form-data; name=\\\"\" + HttpPostRequestTest.FIELD + \"\\\"; filename=\\\"\" + fileName + \"\\\"\\r\\n\" //\n                + \"Content-Type: image/jpeg\\r\\n\" + \"\\r\\n\" //\n                + fileContent + \"\\r\\n\" //\n                + \"--\" + divider + \"\\r\\n\" //\n                + \"Content-Disposition: form-data; name=\\\"\" + HttpPostRequestTest.FIELD2 + \"\\\"; filename=\\\"\" + file2Name + \"\\\"\\r\\n\" //\n                + \"Content-Type: image/jpeg\\r\\n\" + \"\\r\\n\" //\n                + file2Content + \"\\r\\n\" //\n                + \"\\r\\n\" //\n                + \"--\" + divider + \"--\\r\\n\";\n        int size = content.length() + header.length();\n        int contentLengthHeaderValueSize = String.valueOf(size).length();\n        int contentLength = size + contentLengthHeaderValueSize + HttpPostRequestTest.CONTENT_LENGTH.length();\n        String input = header + HttpPostRequestTest.CONTENT_LENGTH + (contentLength + 4) + \"\\r\\n\\r\\n\" + content;\n        invokeServer(input);\n\n        assertEquals(\"Parm count did not match.\", 2, this.testServer.parms.size());\n        assertEquals(\"Parameter count did not match.\", 2, this.testServer.parameters.size());\n        BufferedReader reader = new BufferedReader(new FileReader(this.testServer.files.get(HttpPostRequestTest.FIELD)));\n        List<String> lines = readLinesFromFile(reader);\n        assertLinesOfText(new String[]{\n            fileContent\n        }, lines);\n        String fileName2 = this.testServer.files.get(HttpPostRequestTest.FIELD2);\n        int testNumber = 0;\n        while (fileName2 == null && testNumber < 5) {\n            testNumber++;\n            fileName2 = this.testServer.files.get(HttpPostRequestTest.FIELD2 + testNumber);\n        }\n        reader = new BufferedReader(new FileReader(fileName2));\n        lines = readLinesFromFile(reader);\n        assertLinesOfText(new String[]{\n            file2Content\n        }, lines);\n\n    }\n\n    @Test\n    public void testPostWithMultipartFormUploadFileWithMultilineContent() throws Exception {\n        String filename = \"GrandCanyon.txt\";\n        String lineSeparator = \"\\n\";\n        String fileContent = HttpPostRequestTest.VALUE + lineSeparator + HttpPostRequestTest.VALUE + lineSeparator + HttpPostRequestTest.VALUE;\n        String input = preparePostWithMultipartForm(filename, fileContent);\n\n        invokeServer(input);\n\n        assertEquals(\"Parm count did not match.\", 1, this.testServer.parms.size());\n        assertEquals(\"Parameter count did not match.\", 1, this.testServer.parameters.size());\n        BufferedReader reader = new BufferedReader(new FileReader(this.testServer.files.get(HttpPostRequestTest.FIELD)));\n        List<String> lines = readLinesFromFile(reader);\n        assertLinesOfText(fileContent.split(lineSeparator), lines);\n    }\n\n}\n"
  },
  {
    "path": "core/src/test/java/org/nanohttpd/junit/protocols/http/HttpPutRequestTest.java",
    "content": "package org.nanohttpd.junit.protocols.http;\n\n/*\n * #%L\n * NanoHttpd-Core\n * %%\n * Copyright (C) 2012 - 2015 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport static junit.framework.Assert.assertTrue;\n\nimport java.io.BufferedReader;\nimport java.io.ByteArrayOutputStream;\nimport java.io.FileReader;\nimport java.util.List;\n\nimport org.junit.Test;\n\npublic class HttpPutRequestTest extends HttpServerTest {\n\n    @Test\n    public void testPutRequestSendsContent() throws Exception {\n        ByteArrayOutputStream outputStream = invokeServer(\"PUT \" + HttpServerTest.URI + \" HTTP/1.1\\r\\n\\r\\nBodyData 1\\nLine 2\");\n\n        String[] expectedOutput = {\n            \"HTTP/1.1 200 OK\",\n            \"Content-Type: text/html\",\n            \"Date: .*\",\n            \"Connection: keep-alive\",\n            \"Content-Length: 0\",\n            \"\"\n        };\n\n        assertResponse(outputStream, expectedOutput);\n\n        assertTrue(this.testServer.files.containsKey(\"content\"));\n        BufferedReader reader = null;\n        try {\n            String[] expectedInputToServeMethodViaFile = {\n                \"BodyData 1\",\n                \"Line 2\"\n            };\n            reader = new BufferedReader(new FileReader(this.testServer.files.get(\"content\")));\n            List<String> lines = readLinesFromFile(reader);\n            assertLinesOfText(expectedInputToServeMethodViaFile, lines);\n        } finally {\n            if (reader != null) {\n                reader.close();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/test/java/org/nanohttpd/junit/protocols/http/HttpSSLServerTest.java",
    "content": "package org.nanohttpd.junit.protocols.http;\n\n/*\n * #%L\n * NanoHttpd-Core\n * %%\n * Copyright (C) 2012 - 2015 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport java.io.File;\nimport java.io.IOException;\n\nimport org.apache.http.HttpEntity;\nimport org.apache.http.HttpResponse;\nimport org.apache.http.client.ClientProtocolException;\nimport org.apache.http.client.methods.HttpTrace;\nimport org.apache.http.impl.client.DefaultHttpClient;\nimport org.junit.After;\nimport org.junit.Assert;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.nanohttpd.protocols.http.NanoHTTPD;\n\npublic class HttpSSLServerTest extends HttpServerTest {\n\n    @Test\n    public void testSSLConnection() throws ClientProtocolException, IOException {\n        DefaultHttpClient httpclient = new DefaultHttpClient();\n        HttpTrace httphead = new HttpTrace(\"https://localhost:9043/index.html\");\n        HttpResponse response = httpclient.execute(httphead);\n        HttpEntity entity = response.getEntity();\n        Assert.assertEquals(200, response.getStatusLine().getStatusCode());\n\n        Assert.assertEquals(9043, this.testServer.getListeningPort());\n        Assert.assertTrue(this.testServer.isAlive());\n    }\n\n    /**\n     * using http to connect to https.\n     * \n     * @throws ClientProtocolException\n     * @throws IOException\n     */\n    @Test(expected = ClientProtocolException.class)\n    public void testHttpOnSSLConnection() throws ClientProtocolException, IOException {\n        DefaultHttpClient httpclient = new DefaultHttpClient();\n        HttpTrace httphead = new HttpTrace(\"http://localhost:9043/index.html\");\n        httpclient.execute(httphead);\n    }\n\n    @Before\n    public void setUp() throws Exception {\n        System.setProperty(\"javax.net.ssl.trustStore\", new File(\"src/test/resources/keystore.jks\").getAbsolutePath());\n        this.testServer = new TestServer(9043);\n        this.testServer.makeSecure(NanoHTTPD.makeSSLSocketFactory(\"/keystore.jks\", \"password\".toCharArray()), null);\n        this.tempFileManager = new TestTempFileManager();\n        this.testServer.start();\n        try {\n            long start = System.currentTimeMillis();\n            Thread.sleep(100L);\n            while (!this.testServer.wasStarted()) {\n                Thread.sleep(100L);\n                if (System.currentTimeMillis() - start > 2000) {\n                    Assert.fail(\"could not start server\");\n                }\n            }\n        } catch (InterruptedException e) {\n        }\n    }\n\n    @After\n    public void tearDown() {\n        this.testServer.stop();\n    }\n}\n"
  },
  {
    "path": "core/src/test/java/org/nanohttpd/junit/protocols/http/HttpServerTest.java",
    "content": "package org.nanohttpd.junit.protocols.http;\n\nimport static org.junit.Assert.assertEquals;\n\n/*\n * #%L\n * NanoHttpd-Core\n * %%\n * Copyright (C) 2012 - 2015 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport static org.junit.Assert.assertNotNull;\nimport static org.junit.Assert.assertTrue;\nimport static org.junit.Assert.fail;\n\nimport java.io.BufferedReader;\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.io.OutputStream;\nimport java.io.StringReader;\nimport java.net.InetAddress;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.apache.http.HttpEntity;\nimport org.apache.http.HttpResponse;\nimport org.apache.http.client.HttpClient;\nimport org.apache.http.client.methods.HttpPost;\nimport org.apache.http.entity.mime.MultipartEntity;\nimport org.apache.http.entity.mime.content.FileBody;\nimport org.apache.http.entity.mime.content.StringBody;\nimport org.apache.http.impl.client.DefaultHttpClient;\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.nanohttpd.protocols.http.HTTPSession;\nimport org.nanohttpd.protocols.http.IHTTPSession;\nimport org.nanohttpd.protocols.http.NanoHTTPD;\nimport org.nanohttpd.protocols.http.request.Method;\nimport org.nanohttpd.protocols.http.response.Response;\nimport org.nanohttpd.protocols.http.tempfiles.DefaultTempFileManager;\nimport org.nanohttpd.protocols.http.tempfiles.ITempFileManager;\n\n/**\n * @author Paul S. Hawke (paul.hawke@gmail.com) On: 3/10/13 at 8:32 PM\n */\npublic class HttpServerTest {\n\n    public static class TestServer extends NanoHTTPD {\n\n        public Response response = Response.newFixedLengthResponse(\"\");\n\n        public String uri;\n\n        public Method method;\n\n        public Map<String, String> header;\n\n        public Map<String, String> parms;\n\n        public Map<String, List<String>> parameters;\n\n        public Map<String, String> files;\n\n        public Map<String, List<String>> decodedParamters;\n\n        public Map<String, List<String>> decodedParamtersFromParameter;\n\n        public String queryParameterString;\n\n        public TestServer() {\n            super(8192);\n        }\n\n        public TestServer(int port) {\n            super(port);\n        }\n\n        public HTTPSession createSession(ITempFileManager tempFileManager, InputStream inputStream, OutputStream outputStream) {\n            return new HTTPSession(this, tempFileManager, inputStream, outputStream);\n        }\n\n        public HTTPSession createSession(ITempFileManager tempFileManager, InputStream inputStream, OutputStream outputStream, InetAddress inetAddress) {\n            return new HTTPSession(this, tempFileManager, inputStream, outputStream, inetAddress);\n        }\n\n        @Override\n        public Response serve(IHTTPSession session) {\n            this.uri = session.getUri();\n            this.method = session.getMethod();\n            this.header = session.getHeaders();\n            this.files = new HashMap<String, String>();\n            try {\n                session.parseBody(this.files);\n            } catch (Exception e) {\n                e.printStackTrace();\n            }\n            this.parms = session.getParms();\n            this.parameters = session.getParameters();\n            this.queryParameterString = session.getQueryParameterString();\n            this.decodedParamtersFromParameter = decodeParameters(this.queryParameterString);\n            this.decodedParamters = decodeParameters(session.getQueryParameterString());\n\n            return this.response;\n        }\n    }\n\n    public static class TestTempFileManager extends DefaultTempFileManager {\n\n        public void _clear() {\n            super.clear();\n        }\n\n        @Override\n        public void clear() {\n            // ignore\n        }\n    }\n\n    public static final String URI = \"http://www.myserver.org/pub/WWW/someFile.html\";\n\n    protected TestServer testServer;\n\n    protected TestTempFileManager tempFileManager;\n\n    protected void assertLinesOfText(String[] expected, List<String> lines) {\n        // assertEquals(expected.length, lines.size());\n        for (int i = 0; i < expected.length; i++) {\n            String line = lines.get(i);\n            assertTrue(\"Output line \" + i + \" doesn't match expectation.\\n\" + \"  Output: \" + line + \"\\n\" + \"Expected: \" + expected[i], line.matches(expected[i]));\n        }\n    }\n\n    protected void assertResponse(ByteArrayOutputStream outputStream, String[] expected) throws IOException {\n        List<String> lines = getOutputLines(outputStream);\n        assertLinesOfText(expected, lines);\n    }\n\n    protected List<String> getOutputLines(ByteArrayOutputStream outputStream) throws IOException {\n        BufferedReader reader = new BufferedReader(new StringReader(outputStream.toString()));\n        return readLinesFromFile(reader);\n    }\n\n    protected ByteArrayOutputStream invokeServer(String request) {\n        ByteArrayInputStream inputStream = new ByteArrayInputStream(request.getBytes());\n        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();\n        HTTPSession session = this.testServer.createSession(this.tempFileManager, inputStream, outputStream);\n        try {\n            session.execute();\n        } catch (IOException e) {\n            fail(\"\" + e);\n            e.printStackTrace();\n        }\n        return outputStream;\n    }\n\n    protected List<String> readLinesFromFile(BufferedReader reader) throws IOException {\n        List<String> lines = new ArrayList<String>();\n        String line = \"\";\n        while (line != null) {\n            line = reader.readLine();\n            if (line != null) {\n                lines.add(line.trim());\n            }\n        }\n        return lines;\n    }\n\n    @Before\n    public void setUp() throws Exception {\n        this.testServer = new TestServer();\n        this.tempFileManager = new TestTempFileManager();\n    }\n\n    @After\n    public void tearDown() {\n        this.tempFileManager._clear();\n    }\n\n    @Test\n    public void testServerExists() {\n        assertNotNull(this.testServer);\n    }\n\n    @Test\n    public void testMultipartFormData() throws IOException {\n        final int testPort = 4589;\n        NanoHTTPD server = null;\n\n        try {\n            server = new NanoHTTPD(testPort) {\n\n                final Map<String, String> files = new HashMap<String, String>();\n\n                @Override\n                public Response serve(IHTTPSession session) {\n                    StringBuilder responseMsg = new StringBuilder();\n\n                    try {\n                        session.parseBody(this.files);\n                        for (String key : files.keySet()) {\n                            responseMsg.append(key);\n                        }\n                    } catch (Exception e) {\n                        responseMsg.append(e.getMessage());\n                    }\n\n                    return Response.newFixedLengthResponse(responseMsg.toString());\n                }\n            };\n            server.start(NanoHTTPD.SOCKET_READ_TIMEOUT, false);\n\n            HttpClient httpclient = new DefaultHttpClient();\n            HttpPost httppost = new HttpPost(\"http://localhost:\" + testPort);\n\n            final String fileName = \"file-upload-test.htm\";\n            FileBody bin = new FileBody(new File(getClass().getClassLoader().getResource(fileName).getFile()));\n            StringBody comment = new StringBody(\"Filename: \" + fileName);\n\n            MultipartEntity reqEntity = new MultipartEntity();\n            reqEntity.addPart(\"bin\", bin);\n            reqEntity.addPart(\"comment\", comment);\n            httppost.setEntity(reqEntity);\n\n            HttpResponse response = httpclient.execute(httppost);\n            HttpEntity entity = response.getEntity();\n\n            if (entity != null) {\n                InputStream instream = entity.getContent();\n                BufferedReader reader = new BufferedReader(new InputStreamReader(instream, \"UTF-8\"));\n                String line = reader.readLine();\n                assertNotNull(line, \"Invalid server reponse\");\n                assertEquals(\"Server failed multi-part data parse\" + line, \"bincomment\", line);\n                reader.close();\n                instream.close();\n            }\n        } finally {\n            if (server != null) {\n                server.stop();\n            }\n        }\n    }\n\n    @Test\n    public void testTempFileInterface() throws IOException {\n        final int testPort = 4589;\n        NanoHTTPD server = new NanoHTTPD(testPort) {\n\n            final Map<String, String> files = new HashMap<String, String>();\n\n            @Override\n            public Response serve(IHTTPSession session) {\n                String responseMsg = \"pass\";\n\n                try {\n                    session.parseBody(this.files);\n                    for (String key : files.keySet()) {\n                        if (!(new File(files.get(key))).exists()) {\n                            responseMsg = \"fail\";\n                        }\n                    }\n                } catch (Exception e) {\n                    responseMsg = e.getMessage();\n                }\n\n                return Response.newFixedLengthResponse(responseMsg.toString());\n            }\n        };\n        server.start(NanoHTTPD.SOCKET_READ_TIMEOUT, false);\n\n        HttpClient httpclient = new DefaultHttpClient();\n        HttpPost httppost = new HttpPost(\"http://localhost:\" + testPort);\n\n        final String fileName = \"file-upload-test.htm\";\n        FileBody bin = new FileBody(new File(getClass().getClassLoader().getResource(fileName).getFile()));\n        StringBody comment = new StringBody(\"Filename: \" + fileName);\n\n        MultipartEntity reqEntity = new MultipartEntity();\n        reqEntity.addPart(\"bin\", bin);\n        reqEntity.addPart(\"comment\", comment);\n        httppost.setEntity(reqEntity);\n\n        HttpResponse response = httpclient.execute(httppost);\n        HttpEntity entity = response.getEntity();\n\n        if (entity != null) {\n            InputStream instream = entity.getContent();\n            BufferedReader reader = new BufferedReader(new InputStreamReader(instream, \"UTF-8\"));\n            String line = reader.readLine();\n            assertNotNull(line, \"Invalid server reponse\");\n            assertEquals(\"Server file check failed: \" + line, \"pass\", line);\n            reader.close();\n            instream.close();\n        } else {\n            fail(\"No server response\");\n        }\n        server.stop();\n    }\n}\n"
  },
  {
    "path": "core/src/test/java/org/nanohttpd/junit/protocols/http/HttpSessionHeadersTest.java",
    "content": "package org.nanohttpd.junit.protocols.http;\n\n/*\n * #%L\n * NanoHttpd-Core\n * %%\n * Copyright (C) 2012 - 2015 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNotNull;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.net.InetAddress;\n\nimport org.junit.Test;\nimport org.nanohttpd.protocols.http.HTTPSession;\n\npublic class HttpSessionHeadersTest extends HttpServerTest {\n\n    private static final String DUMMY_REQUEST_CONTENT = \"dummy request content\";\n\n    private static final TestTempFileManager TEST_TEMP_FILE_MANAGER = new TestTempFileManager();\n\n    @Test\n    public void testHeadersRemoteIp() throws Exception {\n        ByteArrayInputStream inputStream = new ByteArrayInputStream(HttpSessionHeadersTest.DUMMY_REQUEST_CONTENT.getBytes());\n        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();\n        String[] ipAddresses = {\n            \"127.0.0.1\",\n            \"8.8.8.8\",\n        };\n        for (String ipAddress : ipAddresses) {\n            InetAddress inetAddress = InetAddress.getByName(ipAddress);\n            HTTPSession session = this.testServer.createSession(HttpSessionHeadersTest.TEST_TEMP_FILE_MANAGER, inputStream, outputStream, inetAddress);\n            assertEquals(ipAddress, session.getRemoteIpAddress());\n        }\n    }\n\n}\n"
  },
  {
    "path": "core/src/test/java/org/nanohttpd/junit/protocols/http/HttpSessionTest.java",
    "content": "package org.nanohttpd.junit.protocols.http;\n\n/*\n * #%L\n * NanoHttpd-Core\n * %%\n * Copyright (C) 2012 - 2015 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport static org.junit.Assert.assertEquals;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.net.InetAddress;\nimport java.net.UnknownHostException;\n\nimport org.junit.Test;\nimport org.nanohttpd.protocols.http.HTTPSession;\n\npublic class HttpSessionTest extends HttpServerTest {\n\n    private static final String DUMMY_REQUEST_CONTENT = \"dummy request content\";\n\n    private static final TestTempFileManager TEST_TEMP_FILE_MANAGER = new TestTempFileManager();\n\n    @Test\n    public void testSessionRemoteIPAddress() throws UnknownHostException {\n        ByteArrayInputStream inputStream = new ByteArrayInputStream(HttpSessionTest.DUMMY_REQUEST_CONTENT.getBytes());\n        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();\n        InetAddress inetAddress = InetAddress.getByName(\"127.0.0.1\");\n        HTTPSession session = this.testServer.createSession(HttpSessionTest.TEST_TEMP_FILE_MANAGER, inputStream, outputStream, inetAddress);\n        assertEquals(\"127.0.0.1\", session.getRemoteIpAddress());\n    }\n}\n"
  },
  {
    "path": "core/src/test/java/org/nanohttpd/junit/protocols/http/InvalidRequestTest.java",
    "content": "package org.nanohttpd.junit.protocols.http;\n\n/*\n * #%L\n * NanoHttpd-Core\n * %%\n * Copyright (C) 2012 - 2015 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\nimport static junit.framework.Assert.assertNotNull;\nimport static junit.framework.Assert.assertTrue;\n\nimport org.junit.Test;\n\npublic class InvalidRequestTest extends HttpServerTest {\n\n    @Test\n    public void testGetRequestWithoutProtocol() {\n        invokeServer(\"GET \" + HttpServerTest.URI + \"\\r\\nX-Important-Header: foo\");\n\n        assertNotNull(this.testServer.parms);\n        assertNotNull(this.testServer.parameters);\n        assertTrue(this.testServer.header.size() > 0);\n        assertNotNull(this.testServer.files);\n        assertNotNull(this.testServer.uri);\n    }\n\n    @Test\n    public void testGetRequestWithProtocol() {\n        invokeServer(\"GET \" + HttpServerTest.URI + \" HTTP/1.1\\r\\nX-Important-Header: foo\");\n\n        assertNotNull(this.testServer.parms);\n        assertNotNull(this.testServer.parameters);\n        assertTrue(this.testServer.header.size() > 0);\n        assertNotNull(this.testServer.files);\n        assertNotNull(this.testServer.uri);\n    }\n\n    @Test\n    public void testPostRequestWithoutProtocol() {\n        invokeServer(\"POST \" + HttpServerTest.URI + \"\\r\\nContent-Length: 123\");\n        assertNotNull(this.testServer.parms);\n        assertNotNull(this.testServer.parameters);\n        assertTrue(this.testServer.header.size() > 0);\n        assertNotNull(this.testServer.files);\n        assertNotNull(this.testServer.uri);\n    }\n\n    @Test\n    public void testPostRequestWithProtocol() {\n        invokeServer(\"POST \" + HttpServerTest.URI + \" HTTP/1.1\\r\\nContent-Length: 123\");\n        assertNotNull(this.testServer.parms);\n        assertNotNull(this.testServer.parameters);\n        assertTrue(this.testServer.header.size() > 0);\n        assertNotNull(this.testServer.files);\n        assertNotNull(this.testServer.uri);\n    }\n}\n"
  },
  {
    "path": "core/src/test/java/org/nanohttpd/junit/protocols/http/JavaIOTempDirExistTest.java",
    "content": "package org.nanohttpd.junit.protocols.http;\n\n/*\n * #%L\n * NanoHttpd-Core\n * %%\n * Copyright (C) 2012 - 2015 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.UUID;\n\nimport org.junit.Assert;\nimport org.junit.Test;\nimport org.nanohttpd.protocols.http.tempfiles.DefaultTempFile;\nimport org.nanohttpd.protocols.http.tempfiles.DefaultTempFileManager;\n\n/**\n * Created by Victor Nikiforov on 10/16/15.\n */\npublic class JavaIOTempDirExistTest {\n\n    @Test\n    public void testJavaIoTempDefault() throws Exception {\n        String tmpdir = System.getProperty(\"java.io.tmpdir\");\n        DefaultTempFileManager manager = new DefaultTempFileManager();\n        DefaultTempFile tempFile = (DefaultTempFile) manager.createTempFile(\"xx\");\n        File tempFileBackRef = new File(tempFile.getName());\n        Assert.assertEquals(tempFileBackRef.getParentFile(), new File(tmpdir));\n\n        // force an exception\n        tempFileBackRef.delete();\n        Exception e = null;\n        try {\n            tempFile.delete();\n        } catch (Exception ex) {\n            e = ex;\n        }\n        Assert.assertNotNull(e);\n        manager.clear();\n    }\n\n    @Test\n    public void testJavaIoTempSpecific() throws IOException {\n        final String tmpdir = System.getProperty(\"java.io.tmpdir\");\n        try {\n            String tempFileName = UUID.randomUUID().toString();\n            File newDir = new File(\"target\", tempFileName);\n            System.setProperty(\"java.io.tmpdir\", newDir.getAbsolutePath());\n            Assert.assertEquals(false, newDir.exists());\n            new DefaultTempFileManager();\n            Assert.assertEquals(true, newDir.exists());\n            newDir.delete();\n        } finally {\n            System.setProperty(\"java.io.tmpdir\", tmpdir);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "core/src/test/java/org/nanohttpd/junit/protocols/http/LoadKeyStoreTest.java",
    "content": "package org.nanohttpd.junit.protocols.http;\n\nimport static org.junit.Assert.assertNotNull;\nimport static org.junit.Assert.assertNull;\n\nimport java.io.IOException;\nimport java.io.InputStream;\n\nimport javax.net.ssl.SSLServerSocketFactory;\n\n/*\n * #%L\n * NanoHttpd-Core\n * %%\n * Copyright (C) 2012 - 2015 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport org.junit.Rule;\nimport org.junit.Test;\nimport org.junit.rules.ExpectedException;\nimport org.nanohttpd.protocols.http.NanoHTTPD;\n\npublic class LoadKeyStoreTest {\n\n    @Rule\n    public ExpectedException thrown = ExpectedException.none();\n\n    @Test\n    public void loadKeyStoreFromResources() throws Exception {\n        String keyStorePath = \"/keystore.jks\";\n        InputStream resourceAsStream = this.getClass().getResourceAsStream(keyStorePath);\n        assertNotNull(resourceAsStream);\n\n        SSLServerSocketFactory sslServerSocketFactory = NanoHTTPD.makeSSLSocketFactory(keyStorePath, \"password\".toCharArray());\n        assertNotNull(sslServerSocketFactory);\n    }\n\n    @Test\n    public void loadKeyStoreFromResourcesWrongPassword() throws Exception {\n        String keyStorePath = \"/keystore.jks\";\n        InputStream resourceAsStream = this.getClass().getResourceAsStream(keyStorePath);\n        assertNotNull(resourceAsStream);\n\n        thrown.expect(IOException.class);\n        NanoHTTPD.makeSSLSocketFactory(keyStorePath, \"wrongpassword\".toCharArray());\n    }\n\n    @Test\n    public void loadNonExistentKeyStoreFromResources() throws Exception {\n        String nonExistentPath = \"/nokeystorehere.jks\";\n        InputStream resourceAsStream = this.getClass().getResourceAsStream(nonExistentPath);\n        assertNull(resourceAsStream);\n\n        thrown.expect(IOException.class);\n        NanoHTTPD.makeSSLSocketFactory(nonExistentPath, \"\".toCharArray());\n    }\n\n}\n"
  },
  {
    "path": "core/src/test/java/org/nanohttpd/junit/protocols/http/MimeTest.java",
    "content": "package org.nanohttpd.junit.protocols.http;\n\n/*\n * #%L\n * NanoHttpd-Core\n * %%\n * Copyright (C) 2012 - 2015 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport org.junit.Assert;\nimport org.junit.Test;\nimport org.nanohttpd.protocols.http.NanoHTTPD;\n\npublic class MimeTest {\n\n    @Test\n    public void testExistingMimeType() throws Exception {\n        Assert.assertEquals(\"text/html\", NanoHTTPD.getMimeTypeForFile(\"xxxx.html\"));\n    }\n\n    @Test\n    public void testNotExistingMimeType() throws Exception {\n        Assert.assertNull(NanoHTTPD.mimeTypes().get(\"notExistent\"));\n        Assert.assertEquals(\"application/octet-stream\", NanoHTTPD.getMimeTypeForFile(\"xxxx.notExistent\"));\n    }\n\n    @Test\n    public void testOverwritenMimeType() throws Exception {\n        Assert.assertEquals(\"video/wrongOverwrite\", NanoHTTPD.getMimeTypeForFile(\"xxxx.ts\"));\n    }\n\n    @Test\n    public void testManualMimeType() throws Exception {\n        NanoHTTPD.mimeTypes().put(\"flv\", \"video/manualOverwrite\");\n        Assert.assertEquals(\"video/manualOverwrite\", NanoHTTPD.getMimeTypeForFile(\"xxxx.flv\"));\n    }\n}\n"
  },
  {
    "path": "core/src/test/java/org/nanohttpd/junit/protocols/http/SSLServerSocketFactoryTest.java",
    "content": "package org.nanohttpd.junit.protocols.http;\n\nimport java.io.File;\n\n/*\n * #%L\n * NanoHttpd-Core\n * %%\n * Copyright (C) 2012 - 2015 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport java.io.IOException;\nimport java.util.Arrays;\n\nimport javax.net.ssl.SSLServerSocket;\n\nimport org.apache.http.HttpEntity;\nimport org.apache.http.HttpResponse;\nimport org.apache.http.client.ClientProtocolException;\nimport org.apache.http.client.methods.HttpTrace;\nimport org.apache.http.impl.client.DefaultHttpClient;\nimport org.junit.After;\nimport org.junit.Assert;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.nanohttpd.protocols.http.NanoHTTPD;\nimport org.nanohttpd.protocols.http.sockets.SecureServerSocketFactory;\n\npublic class SSLServerSocketFactoryTest extends HttpServerTest {\n\n    @Test\n    public void testSSLConnection() throws ClientProtocolException, IOException {\n        DefaultHttpClient httpclient = new DefaultHttpClient();\n        HttpTrace httphead = new HttpTrace(\"https://localhost:9043/index.html\");\n        HttpResponse response = httpclient.execute(httphead);\n        HttpEntity entity = response.getEntity();\n        Assert.assertEquals(200, response.getStatusLine().getStatusCode());\n\n        Assert.assertEquals(9043, this.testServer.getListeningPort());\n        Assert.assertTrue(this.testServer.isAlive());\n    }\n\n    @Test\n    public void testCreatePassesTheProtocolsToServerSocket() throws IOException {\n        // first find the supported protocols\n        SecureServerSocketFactory secureServerSocketFactory = new SecureServerSocketFactory(NanoHTTPD.makeSSLSocketFactory(\"/keystore.jks\", \"password\".toCharArray()), null);\n        SSLServerSocket socket = (SSLServerSocket) secureServerSocketFactory.create();\n        String[] protocols = socket.getSupportedProtocols();\n\n        // remove one element from supported protocols\n        if (protocols.length > 0) {\n            protocols = Arrays.copyOfRange(protocols, 0, protocols.length - 1);\n        }\n\n        // test\n        secureServerSocketFactory = new SecureServerSocketFactory(NanoHTTPD.makeSSLSocketFactory(\"/keystore.jks\", \"password\".toCharArray()), protocols);\n        socket = (SSLServerSocket) secureServerSocketFactory.create();\n        Assert.assertArrayEquals(\"Enabled protocols specified in the factory were not set to the socket.\", protocols, socket.getEnabledProtocols());\n    }\n\n    @Before\n    public void setUp() throws Exception {\n        System.setProperty(\"javax.net.ssl.trustStore\", new File(\"src/test/resources/keystore.jks\").getAbsolutePath());\n        this.testServer = new TestServer(9043);\n        this.testServer.setServerSocketFactory(new SecureServerSocketFactory(NanoHTTPD.makeSSLSocketFactory(\"/keystore.jks\", \"password\".toCharArray()), null));\n        this.tempFileManager = new TestTempFileManager();\n        this.testServer.start();\n        try {\n            long start = System.currentTimeMillis();\n            Thread.sleep(100L);\n            while (!this.testServer.wasStarted()) {\n                Thread.sleep(100L);\n                if (System.currentTimeMillis() - start > 2000) {\n                    Assert.fail(\"could not start server\");\n                }\n            }\n        } catch (InterruptedException e) {\n        }\n    }\n\n    @After\n    public void tearDown() {\n        this.testServer.stop();\n    }\n}\n"
  },
  {
    "path": "core/src/test/java/org/nanohttpd/junit/protocols/http/ServerSocketFactoryTest.java",
    "content": "package org.nanohttpd.junit.protocols.http;\n\nimport java.io.File;\n\n/*\n * #%L\n * NanoHttpd-Core\n * %%\n * Copyright (C) 2012 - 2015 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport java.io.IOException;\nimport java.net.ServerSocket;\n\nimport org.junit.Assert;\nimport org.junit.Test;\nimport org.nanohttpd.protocols.http.NanoHTTPD;\nimport org.nanohttpd.protocols.http.sockets.SecureServerSocketFactory;\nimport org.nanohttpd.util.IFactoryThrowing;\n\npublic class ServerSocketFactoryTest extends NanoHTTPD {\n\n    public static final int PORT = 8192;\n\n    public ServerSocketFactoryTest() {\n        super(PORT);\n\n        this.setServerSocketFactory(new TestFactory());\n    }\n\n    @Test\n    public void isCustomServerSocketFactory() {\n        System.out.println(\"CustomServerSocketFactory test\");\n        Assert.assertTrue(this.getServerSocketFactory() instanceof TestFactory);\n    }\n\n    @Test\n    public void testCreateServerSocket() {\n        System.out.println(\"CreateServerSocket test\");\n        ServerSocket ss = null;\n        try {\n            ss = this.getServerSocketFactory().create();\n        } catch (IOException e) {\n        }\n        Assert.assertTrue(ss != null);\n    }\n\n    @Test\n    public void testSSLServerSocketFail() {\n        String[] protocols = {\n            \"\"\n        };\n        System.setProperty(\"javax.net.ssl.trustStore\", new File(\"src/test/resources/keystore.jks\").getAbsolutePath());\n        IFactoryThrowing<ServerSocket, IOException> ssFactory = new SecureServerSocketFactory(null, protocols);\n        ServerSocket ss = null;\n        try {\n            ss = ssFactory.create();\n        } catch (Exception e) {\n        }\n        Assert.assertTrue(ss == null);\n\n    }\n\n    private class TestFactory implements IFactoryThrowing<ServerSocket, IOException> {\n\n        @Override\n        public ServerSocket create() {\n            try {\n                return new ServerSocket();\n            } catch (IOException e) {\n                e.printStackTrace();\n            }\n            return null;\n        }\n    }\n}\n"
  },
  {
    "path": "core/src/test/java/org/nanohttpd/junit/protocols/http/StatusTest.java",
    "content": "package org.nanohttpd.junit.protocols.http;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n/*\n * #%L\n * NanoHttpd-Core\n * %%\n * Copyright (C) 2012 - 2015 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport org.junit.Assert;\nimport org.junit.Test;\nimport org.nanohttpd.protocols.http.response.Status;\n\npublic class StatusTest {\n\n    @Test\n    public void testMessages() {\n        // These are values where the name of the enum does not match the status\n        // code description.\n        // By default you should not need to add any new values to this map if\n        // you\n        // make the name of the enum name match the status code description.\n        Map<Status, String> overrideValues = new HashMap<Status, String>();\n        overrideValues.put(Status.INTERNAL_ERROR, \"500 Internal Server Error\");\n        overrideValues.put(Status.SWITCH_PROTOCOL, \"101 Switching Protocols\");\n        overrideValues.put(Status.OK, \"200 OK\");\n        overrideValues.put(Status.MULTI_STATUS, \"207 Multi-Status\");\n        overrideValues.put(Status.REDIRECT, \"301 Moved Permanently\");\n        overrideValues.put(Status.REDIRECT_SEE_OTHER, \"303 See Other\");\n        overrideValues.put(Status.RANGE_NOT_SATISFIABLE, \"416 Requested Range Not Satisfiable\");\n        overrideValues.put(Status.UNSUPPORTED_HTTP_VERSION, \"505 HTTP Version Not Supported\");\n\n        for (Status status : Status.values()) {\n            if (overrideValues.containsKey(status)) {\n                Assert.assertEquals(overrideValues.get(status), status.getDescription());\n            } else {\n                Assert.assertEquals(getExpectedMessage(status), status.getDescription());\n            }\n        }\n    }\n\n    private String getExpectedMessage(Status status) {\n        String name = status.name().toLowerCase();\n        String[] words = name.split(\"_\");\n        StringBuilder builder = new StringBuilder();\n        builder.append(status.getRequestStatus());\n        builder.append(' ');\n\n        for (int i = 0; i < words.length; i++) {\n            builder.append(Character.toUpperCase(words[i].charAt(0)));\n            builder.append(words[i].substring(1));\n            builder.append(' ');\n        }\n\n        return builder.toString().trim();\n    }\n\n    @Test\n    public void testLookup() throws Exception {\n        Assert.assertEquals(Status.SWITCH_PROTOCOL, Status.lookup(101));\n\n        Assert.assertEquals(Status.OK, Status.lookup(200));\n        Assert.assertEquals(Status.CREATED, Status.lookup(201));\n        Assert.assertEquals(Status.ACCEPTED, Status.lookup(202));\n        Assert.assertEquals(Status.NO_CONTENT, Status.lookup(204));\n        Assert.assertEquals(Status.PARTIAL_CONTENT, Status.lookup(206));\n        Assert.assertEquals(Status.MULTI_STATUS, Status.lookup(207));\n\n        Assert.assertEquals(Status.REDIRECT, Status.lookup(301));\n        Assert.assertEquals(Status.FOUND, Status.lookup(302));\n        Assert.assertEquals(Status.REDIRECT_SEE_OTHER, Status.lookup(303));\n        Assert.assertEquals(Status.NOT_MODIFIED, Status.lookup(304));\n        Assert.assertEquals(Status.TEMPORARY_REDIRECT, Status.lookup(307));\n\n        Assert.assertEquals(Status.BAD_REQUEST, Status.lookup(400));\n        Assert.assertEquals(Status.UNAUTHORIZED, Status.lookup(401));\n        Assert.assertEquals(Status.FORBIDDEN, Status.lookup(403));\n        Assert.assertEquals(Status.NOT_FOUND, Status.lookup(404));\n        Assert.assertEquals(Status.METHOD_NOT_ALLOWED, Status.lookup(405));\n        Assert.assertEquals(Status.NOT_ACCEPTABLE, Status.lookup(406));\n        Assert.assertEquals(Status.REQUEST_TIMEOUT, Status.lookup(408));\n        Assert.assertEquals(Status.CONFLICT, Status.lookup(409));\n        Assert.assertEquals(Status.GONE, Status.lookup(410));\n        Assert.assertEquals(Status.LENGTH_REQUIRED, Status.lookup(411));\n        Assert.assertEquals(Status.PRECONDITION_FAILED, Status.lookup(412));\n        Assert.assertEquals(Status.PAYLOAD_TOO_LARGE, Status.lookup(413));\n        Assert.assertEquals(Status.UNSUPPORTED_MEDIA_TYPE, Status.lookup(415));\n        Assert.assertEquals(Status.RANGE_NOT_SATISFIABLE, Status.lookup(416));\n        Assert.assertEquals(Status.EXPECTATION_FAILED, Status.lookup(417));\n        Assert.assertEquals(Status.TOO_MANY_REQUESTS, Status.lookup(429));\n        Assert.assertEquals(Status.INTERNAL_ERROR, Status.lookup(500));\n        Assert.assertEquals(Status.NOT_IMPLEMENTED, Status.lookup(501));\n        Assert.assertEquals(Status.SERVICE_UNAVAILABLE, Status.lookup(503));\n        Assert.assertEquals(Status.UNSUPPORTED_HTTP_VERSION, Status.lookup(505));\n    }\n}\n"
  },
  {
    "path": "core/src/test/java/org/nanohttpd/junit/protocols/http/integration/CookieIntegrationTest.java",
    "content": "package org.nanohttpd.junit.protocols.http.integration;\n\n/*\n * #%L\n * NanoHttpd-Core\n * %%\n * Copyright (C) 2012 - 2015 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertTrue;\n\nimport java.util.ArrayList;\nimport java.util.Calendar;\nimport java.util.Date;\nimport java.util.List;\n\nimport org.apache.http.client.CookieStore;\nimport org.apache.http.client.ResponseHandler;\nimport org.apache.http.client.methods.HttpGet;\nimport org.apache.http.impl.client.BasicResponseHandler;\nimport org.apache.http.impl.cookie.BasicClientCookie;\nimport org.junit.Test;\nimport org.nanohttpd.protocols.http.IHTTPSession;\nimport org.nanohttpd.protocols.http.NanoHTTPD;\nimport org.nanohttpd.protocols.http.content.Cookie;\nimport org.nanohttpd.protocols.http.content.CookieHandler;\nimport org.nanohttpd.protocols.http.response.Response;\n\n/**\n * @author Paul S. Hawke (paul.hawke@gmail.com) On: 9/2/13 at 10:10 PM\n */\npublic class CookieIntegrationTest extends IntegrationTestBase<CookieIntegrationTest.CookieTestServer> {\n\n    public static class CookieTestServer extends NanoHTTPD {\n\n        List<Cookie> cookiesReceived = new ArrayList<Cookie>();\n\n        List<Cookie> cookiesToSend = new ArrayList<Cookie>();\n\n        public CookieTestServer() {\n            super(8192);\n        }\n\n        @Override\n        public Response serve(IHTTPSession session) {\n            CookieHandler cookies = session.getCookies();\n            for (String cookieName : cookies) {\n                this.cookiesReceived.add(new Cookie(cookieName, cookies.read(cookieName)));\n            }\n            for (Cookie c : this.cookiesToSend) {\n                cookies.set(c);\n            }\n            return Response.newFixedLengthResponse(\"Cookies!\");\n        }\n    }\n\n    @Override\n    public CookieTestServer createTestServer() {\n        return new CookieTestServer();\n    }\n\n    @Test\n    public void testCookieSentBackToClient() throws Exception {\n        this.testServer.cookiesToSend.add(new Cookie(\"name\", \"value\", 30));\n        HttpGet httpget = new HttpGet(\"http://localhost:8192/\");\n        ResponseHandler<String> responseHandler = new BasicResponseHandler();\n        this.httpclient.execute(httpget, responseHandler);\n\n        CookieStore cookies = this.httpclient.getCookieStore();\n        assertEquals(1, cookies.getCookies().size());\n        assertEquals(\"name\", cookies.getCookies().get(0).getName());\n        assertEquals(\"value\", cookies.getCookies().get(0).getValue());\n    }\n\n    @Test\n    public void testMultipleCookieSentBackToClient() throws Exception {\n        this.testServer.cookiesToSend.add(new Cookie(\"name0\", \"value0\", 30));\n        this.testServer.cookiesToSend.add(new Cookie(\"name1\", \"value1\", 30));\n        this.testServer.cookiesToSend.add(new Cookie(\"name2\", \"value2\", 30));\n        this.testServer.cookiesToSend.add(new Cookie(\"name3\", \"value3\", 30));\n        HttpGet httpget = new HttpGet(\"http://localhost:8192/\");\n        ResponseHandler<String> responseHandler = new BasicResponseHandler();\n        this.httpclient.execute(httpget, responseHandler);\n\n        assertEquals(4, this.httpclient.getCookieStore().getCookies().size());\n    }\n\n    @Test\n    public void testNoCookies() throws Exception {\n        HttpGet httpget = new HttpGet(\"http://localhost:8192/\");\n        ResponseHandler<String> responseHandler = new BasicResponseHandler();\n        this.httpclient.execute(httpget, responseHandler);\n\n        CookieStore cookies = this.httpclient.getCookieStore();\n        assertEquals(0, cookies.getCookies().size());\n    }\n\n    @Test\n    public void testServerReceivesCookiesSentFromClient() throws Exception {\n        BasicClientCookie clientCookie = new BasicClientCookie(\"name\", \"value\");\n        Calendar calendar = Calendar.getInstance();\n        calendar.add(Calendar.DAY_OF_YEAR, 100);\n        clientCookie.setExpiryDate(calendar.getTime());\n        clientCookie.setDomain(\"localhost\");\n        this.httpclient.getCookieStore().addCookie(clientCookie);\n        HttpGet httpget = new HttpGet(\"http://localhost:8192/\");\n        ResponseHandler<String> responseHandler = new BasicResponseHandler();\n        this.httpclient.execute(httpget, responseHandler);\n\n        assertEquals(1, this.testServer.cookiesReceived.size());\n        assertTrue(this.testServer.cookiesReceived.get(0).getHTTPHeader().contains(\"name=value\"));\n    }\n\n    @Test\n    public void testServerReceivesMultipleCookiesSentFromClient() throws Exception {\n        Calendar calendar = Calendar.getInstance();\n        calendar.add(Calendar.DAY_OF_YEAR, 100);\n        Date date = calendar.getTime();\n        BasicClientCookie clientCookie0 = new BasicClientCookie(\"name0\", \"value0\");\n        BasicClientCookie clientCookie1 = new BasicClientCookie(\"name1\", \"value1\");\n        BasicClientCookie clientCookie2 = new BasicClientCookie(\"name2\", \"value2\");\n        BasicClientCookie clientCookie3 = new BasicClientCookie(\"name3\", \"value3\");\n        clientCookie0.setExpiryDate(date);\n        clientCookie0.setDomain(\"localhost\");\n        clientCookie1.setExpiryDate(date);\n        clientCookie1.setDomain(\"localhost\");\n        clientCookie2.setExpiryDate(date);\n        clientCookie2.setDomain(\"localhost\");\n        clientCookie3.setExpiryDate(date);\n        clientCookie3.setDomain(\"localhost\");\n        this.httpclient.getCookieStore().addCookie(clientCookie0);\n        this.httpclient.getCookieStore().addCookie(clientCookie1);\n        this.httpclient.getCookieStore().addCookie(clientCookie2);\n        this.httpclient.getCookieStore().addCookie(clientCookie3);\n        HttpGet httpget = new HttpGet(\"http://localhost:8192/\");\n        ResponseHandler<String> responseHandler = new BasicResponseHandler();\n        this.httpclient.execute(httpget, responseHandler);\n\n        assertEquals(4, this.testServer.cookiesReceived.size());\n    }\n}\n"
  },
  {
    "path": "core/src/test/java/org/nanohttpd/junit/protocols/http/integration/GZipIntegrationTest.java",
    "content": "package org.nanohttpd.junit.protocols.http.integration;\n\n/*\n * #%L\n * NanoHttpd-Core\n * %%\n * Copyright (C) 2012 - 2015 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport static org.hamcrest.CoreMatchers.is;\nimport static org.hamcrest.CoreMatchers.nullValue;\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNotNull;\nimport static org.junit.Assert.assertNull;\nimport static org.junit.Assert.assertThat;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\n\nimport org.apache.http.Header;\nimport org.apache.http.HttpResponse;\nimport org.apache.http.client.methods.HttpGet;\nimport org.apache.http.impl.client.DecompressingHttpClient;\nimport org.apache.http.util.EntityUtils;\nimport org.junit.Test;\nimport org.nanohttpd.protocols.http.IHTTPSession;\nimport org.nanohttpd.protocols.http.NanoHTTPD;\nimport org.nanohttpd.protocols.http.response.Response;\nimport org.nanohttpd.protocols.http.response.Status;\n\npublic class GZipIntegrationTest extends IntegrationTestBase<GZipIntegrationTest.TestServer> {\n\n    public static class TestServer extends NanoHTTPD {\n\n        public Response response;\n\n        public TestServer() {\n            super(8192);\n        }\n\n        @Override\n        public Response serve(IHTTPSession session) {\n            return response.setUseGzip(true);\n        }\n    }\n\n    @Override\n    public TestServer createTestServer() {\n        return new TestServer();\n    }\n\n    @Test\n    public void contentEncodingShouldBeAddedToFixedLengthResponses() throws IOException {\n        testServer.response = Response.newFixedLengthResponse(\"This is a test\");\n        HttpGet request = new HttpGet(\"http://localhost:8192/\");\n        request.addHeader(\"Accept-encoding\", \"gzip\");\n        HttpResponse response = httpclient.execute(request);\n        Header contentEncoding = response.getFirstHeader(\"content-encoding\");\n        assertNotNull(\"Content-Encoding should be set\", contentEncoding);\n        assertEquals(\"gzip\", contentEncoding.getValue());\n    }\n\n    @Test\n    public void contentEncodingShouldBeAddedToChunkedResponses() throws IOException {\n        InputStream data = new ByteArrayInputStream(\"This is a test\".getBytes(\"UTF-8\"));\n        testServer.response = Response.newChunkedResponse(Status.OK, \"text/plain\", data);\n        HttpGet request = new HttpGet(\"http://localhost:8192/\");\n        request.addHeader(\"Accept-encoding\", \"gzip\");\n        HttpResponse response = httpclient.execute(request);\n        Header contentEncoding = response.getFirstHeader(\"content-encoding\");\n        assertNotNull(\"Content-Encoding should be set\", contentEncoding);\n        assertEquals(\"gzip\", contentEncoding.getValue());\n    }\n\n    @Test\n    public void shouldFindCorrectAcceptEncodingAmongMany() throws IOException {\n        testServer.response = Response.newFixedLengthResponse(\"This is a test\");\n        HttpGet request = new HttpGet(\"http://localhost:8192/\");\n        request.addHeader(\"Accept-encoding\", \"deflate,gzip\");\n        HttpResponse response = httpclient.execute(request);\n        Header contentEncoding = response.getFirstHeader(\"content-encoding\");\n        assertNotNull(\"Content-Encoding should be set\", contentEncoding);\n        assertEquals(\"gzip\", contentEncoding.getValue());\n    }\n\n    @Test\n    public void contentLengthShouldBeRemovedFromZippedResponses() throws IOException {\n        testServer.response = Response.newFixedLengthResponse(\"This is a test\");\n        HttpGet request = new HttpGet(\"http://localhost:8192/\");\n        request.addHeader(\"Accept-encoding\", \"gzip\");\n        HttpResponse response = httpclient.execute(request);\n        Header contentLength = response.getFirstHeader(\"content-length\");\n        assertNull(\"Content-Length should not be set when gzipping response\", contentLength);\n    }\n\n    @Test\n    public void fixedLengthContentIsEncodedProperly() throws IOException {\n        testServer.response = Response.newFixedLengthResponse(\"This is a test\");\n        HttpGet request = new HttpGet(\"http://localhost:8192/\");\n        request.addHeader(\"Accept-encoding\", \"gzip\");\n        HttpResponse response = new DecompressingHttpClient(httpclient).execute(request);\n        assertEquals(\"This is a test\", EntityUtils.toString(response.getEntity()));\n    }\n\n    @Test\n    public void chunkedContentIsEncodedProperly() throws IOException {\n        InputStream data = new ByteArrayInputStream(\"This is a test\".getBytes(\"UTF-8\"));\n        testServer.response = Response.newChunkedResponse(Status.OK, \"text/plain\", data);\n        HttpGet request = new HttpGet(\"http://localhost:8192/\");\n        request.addHeader(\"Accept-encoding\", \"gzip\");\n        HttpResponse response = new DecompressingHttpClient(httpclient).execute(request);\n        assertEquals(\"This is a test\", EntityUtils.toString(response.getEntity()));\n    }\n\n    @Test\n    public void noGzipWithoutAcceptEncoding() throws IOException {\n        testServer.response = Response.newFixedLengthResponse(\"This is a test\");\n        HttpGet request = new HttpGet(\"http://localhost:8192/\");\n        HttpResponse response = httpclient.execute(request);\n        Header contentEncoding = response.getFirstHeader(\"content-encoding\");\n        assertThat(contentEncoding, is(nullValue()));\n        assertEquals(\"This is a test\", EntityUtils.toString(response.getEntity()));\n    }\n\n    @Test\n    public void contentShouldNotBeGzippedIfContentLengthIsAddedManually() throws IOException {\n        testServer.response = Response.newFixedLengthResponse(\"This is a test\");\n        testServer.response.addHeader(\"Content-Length\", \"\" + (\"This is a test\".getBytes(\"UTF-8\").length));\n        HttpGet request = new HttpGet(\"http://localhost:8192/\");\n        request.addHeader(\"Accept-encoding\", \"gzip\");\n        HttpResponse response = httpclient.execute(request);\n        Header contentEncoding = response.getFirstHeader(\"content-encoding\");\n        assertNull(\"Content-Encoding should not be set when manually setting content-length\", contentEncoding);\n        assertEquals(\"This is a test\", EntityUtils.toString(response.getEntity()));\n\n    }\n\n}\n"
  },
  {
    "path": "core/src/test/java/org/nanohttpd/junit/protocols/http/integration/GetAndPostIntegrationTest.java",
    "content": "package org.nanohttpd.junit.protocols.http.integration;\n\n/*\n * #%L\n * NanoHttpd-Core\n * %%\n * Copyright (C) 2012 - 2015 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.fail;\n\nimport java.io.IOException;\nimport java.nio.charset.Charset;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.apache.http.HttpEntity;\nimport org.apache.http.HttpResponse;\nimport org.apache.http.NameValuePair;\nimport org.apache.http.client.ResponseHandler;\nimport org.apache.http.client.entity.UrlEncodedFormEntity;\nimport org.apache.http.client.methods.HttpGet;\nimport org.apache.http.client.methods.HttpPost;\nimport org.apache.http.entity.mime.HttpMultipartMode;\nimport org.apache.http.entity.mime.MultipartEntity;\nimport org.apache.http.entity.mime.content.StringBody;\nimport org.apache.http.impl.client.BasicResponseHandler;\nimport org.apache.http.message.BasicNameValuePair;\nimport org.apache.http.util.EntityUtils;\nimport org.junit.Test;\nimport org.nanohttpd.protocols.http.IHTTPSession;\nimport org.nanohttpd.protocols.http.NanoHTTPD;\nimport org.nanohttpd.protocols.http.request.Method;\nimport org.nanohttpd.protocols.http.response.Response;\nimport org.nanohttpd.protocols.http.response.Status;\n\n/**\n * @author Paul S. Hawke (paul.hawke@gmail.com) On: 5/19/13 at 5:36 PM\n */\npublic class GetAndPostIntegrationTest extends IntegrationTestBase<GetAndPostIntegrationTest.TestServer> {\n\n    public static class TestServer extends NanoHTTPD {\n\n        public String response;\n\n        public TestServer() {\n            super(8192);\n        }\n\n        @Override\n        public Response serve(IHTTPSession session) {\n            StringBuilder sb = new StringBuilder(String.valueOf(session.getMethod()) + ':' + this.response);\n\n            Method method = session.getMethod();\n            Map<String, String> files = new HashMap<String, String>();\n            if (Method.PUT.equals(method) || Method.POST.equals(method)) {\n                try {\n                    session.parseBody(files);\n                } catch (Exception e) {\n                    fail(e.getMessage());\n                }\n            }\n\n            String uri = session.getUri();\n            Map<String, String> parms = session.getParms();\n            if (parms.size() > 1) {\n                parms.remove(\"NanoHttpd.QUERY_STRING\");\n                sb.append(\"-params=\").append(parms.size());\n                List<String> p = new ArrayList<String>(parms.keySet());\n                Collections.sort(p);\n                for (String k : p) {\n                    sb.append(';').append(k).append('=').append(parms.get(k));\n                }\n            }\n            if (\"/encodingtest\".equals(uri)) {\n                return Response.newFixedLengthResponse(Status.OK, MIME_HTML, \"<html><head><title>Testé ça</title></head><body>Testé ça</body></html>\");\n            } else if (\"/chin\".equals(uri)) {\n                return Response.newFixedLengthResponse(Status.OK, \"application/octet-stream\", sb.toString());\n            } else {\n                return Response.newFixedLengthResponse(sb.toString());\n            }\n        }\n    }\n\n    @Override\n    public TestServer createTestServer() {\n        return new TestServer();\n    }\n\n    @Test\n    public void testGetRequestWithParameters() throws Exception {\n        this.testServer.response = \"testGetRequestWithParameters\";\n\n        HttpGet httpget = new HttpGet(\"http://localhost:8192/?age=120&gender=Male\");\n        ResponseHandler<String> responseHandler = new BasicResponseHandler();\n        String responseBody = this.httpclient.execute(httpget, responseHandler);\n\n        assertEquals(\"GET:testGetRequestWithParameters-params=2;age=120;gender=Male\", responseBody);\n    }\n\n    @Test\n    public void testPostRequestWithFormEncodedParameters() throws Exception {\n        this.testServer.response = \"testPostRequestWithFormEncodedParameters\";\n\n        HttpPost httppost = new HttpPost(\"http://localhost:8192/\");\n        List<NameValuePair> postParameters = new ArrayList<NameValuePair>();\n        postParameters.add(new BasicNameValuePair(\"age\", \"120\"));\n        postParameters.add(new BasicNameValuePair(\"gender\", \"Male\"));\n        httppost.setEntity(new UrlEncodedFormEntity(postParameters));\n\n        ResponseHandler<String> responseHandler = new BasicResponseHandler();\n        String responseBody = this.httpclient.execute(httppost, responseHandler);\n\n        assertEquals(\"POST:testPostRequestWithFormEncodedParameters-params=2;age=120;gender=Male\", responseBody);\n    }\n\n    @Test\n    public void testPostRequestWithMultipartEncodedParameters() throws Exception {\n        this.testServer.response = \"testPostRequestWithMultipartEncodedParameters\";\n\n        HttpPost httppost = new HttpPost(\"http://localhost:8192/\");\n        MultipartEntity reqEntity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);\n        reqEntity.addPart(\"age\", new StringBody(\"120\"));\n        reqEntity.addPart(\"gender\", new StringBody(\"Male\"));\n        httppost.setEntity(reqEntity);\n\n        ResponseHandler<String> responseHandler = new BasicResponseHandler();\n        String responseBody = this.httpclient.execute(httppost, responseHandler);\n\n        assertEquals(\"POST:testPostRequestWithMultipartEncodedParameters-params=2;age=120;gender=Male\", responseBody);\n    }\n\n    @Test\n    public void testPostWithNoParameters() throws Exception {\n        this.testServer.response = \"testPostWithNoParameters\";\n\n        HttpPost httppost = new HttpPost(\"http://localhost:8192/\");\n        ResponseHandler<String> responseHandler = new BasicResponseHandler();\n        String responseBody = this.httpclient.execute(httppost, responseHandler);\n\n        assertEquals(\"POST:testPostWithNoParameters\", responseBody);\n    }\n\n    @Test\n    public void testSimpleGetRequest() throws Exception {\n        this.testServer.response = \"testSimpleGetRequest\";\n\n        HttpGet httpget = new HttpGet(\"http://localhost:8192/\");\n        ResponseHandler<String> responseHandler = new BasicResponseHandler();\n        String responseBody = this.httpclient.execute(httpget, responseHandler);\n\n        assertEquals(\"GET:testSimpleGetRequest\", responseBody);\n    }\n\n    @Test\n    public void testPostRequestWithMultipartExtremEncodedParameters() throws Exception {\n        this.testServer.response = \"testPostRequestWithMultipartEncodedParameters\";\n\n        HttpPost httppost = new HttpPost(\"http://localhost:8192/chin\");\n        MultipartEntity reqEntity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE, \"sfsadfasdf\", Charset.forName(\"UTF-8\"));\n        reqEntity.addPart(\"specialString\", new StringBody(\"拖拉图片到浏览器，可以实现预览功能\", \"text/plain\", Charset.forName(\"UTF-8\")));\n        reqEntity.addPart(\"gender\", new StringBody(\"图片名称\", Charset.forName(\"UTF-8\")) {\n\n            @Override\n            public String getFilename() {\n                return \"图片名称\";\n            }\n        });\n        httppost.setEntity(reqEntity);\n        HttpResponse response = this.httpclient.execute(httppost);\n\n        HttpEntity entity = response.getEntity();\n        String responseBody = EntityUtils.toString(entity, \"UTF-8\");\n\n        assertEquals(\"POST:testPostRequestWithMultipartEncodedParameters-params=2;gender=图片名称;specialString=拖拉图片到浏览器，可以实现预览功能\", responseBody);\n    }\n\n    @Test\n    public void testPostRequestWithEncodedParameters() throws Exception {\n        this.testServer.response = \"testPostRequestWithEncodedParameters\";\n\n        HttpPost httppost = new HttpPost(\"http://localhost:8192/encodingtest\");\n        HttpResponse response = this.httpclient.execute(httppost);\n\n        HttpEntity entity = response.getEntity();\n        String responseBody = EntityUtils.toString(entity);\n\n        assertEquals(\"<html><head><title>Testé ça</title></head><body>Testé ça</body></html>\", responseBody);\n    }\n}\n"
  },
  {
    "path": "core/src/test/java/org/nanohttpd/junit/protocols/http/integration/IntegrationTestBase.java",
    "content": "package org.nanohttpd.junit.protocols.http.integration;\n\n/*\n * #%L\n * NanoHttpd-Core\n * %%\n * Copyright (C) 2012 - 2015 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport java.io.IOException;\n\nimport org.apache.http.impl.client.DefaultHttpClient;\nimport org.junit.After;\nimport org.junit.Before;\nimport org.nanohttpd.protocols.http.NanoHTTPD;\n\n/**\n * @author Paul S. Hawke (paul.hawke@gmail.com) On: 9/2/13 at 10:02 PM\n */\npublic abstract class IntegrationTestBase<T extends NanoHTTPD> {\n\n    protected DefaultHttpClient httpclient;\n\n    protected T testServer;\n\n    public abstract T createTestServer();\n\n    @Before\n    public void setUp() {\n        this.testServer = createTestServer();\n        this.httpclient = new DefaultHttpClient();\n        try {\n            this.testServer.start();\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n    }\n\n    @After\n    public void tearDown() {\n        this.httpclient.getConnectionManager().shutdown();\n        this.testServer.stop();\n    }\n}\n"
  },
  {
    "path": "core/src/test/java/org/nanohttpd/junit/protocols/http/integration/PutStreamIntegrationTest.java",
    "content": "package org.nanohttpd.junit.protocols.http.integration;\n\n/*\n * #%L\n * NanoHttpd-Core\n * %%\n * Copyright (C) 2012 - 2015 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport static org.junit.Assert.assertEquals;\n\nimport java.io.DataInputStream;\nimport java.io.IOException;\nimport java.util.Map;\n\nimport org.apache.http.client.ResponseHandler;\nimport org.apache.http.client.methods.HttpPut;\nimport org.apache.http.entity.ByteArrayEntity;\nimport org.apache.http.impl.client.BasicResponseHandler;\nimport org.junit.Test;\nimport org.nanohttpd.protocols.http.IHTTPSession;\nimport org.nanohttpd.protocols.http.NanoHTTPD;\nimport org.nanohttpd.protocols.http.request.Method;\nimport org.nanohttpd.protocols.http.response.Response;\nimport org.nanohttpd.protocols.http.response.Status;\n\npublic class PutStreamIntegrationTest extends IntegrationTestBase<PutStreamIntegrationTest.TestServer> {\n\n    public static class TestServer extends NanoHTTPD {\n\n        public TestServer() {\n            super(8192);\n        }\n\n        @Override\n        public Response serve(IHTTPSession session) {\n            Method method = session.getMethod();\n            Map<String, String> headers = session.getHeaders();\n            int contentLength = Integer.parseInt(headers.get(\"content-length\"));\n\n            byte[] body;\n            try {\n                DataInputStream dataInputStream = new DataInputStream(session.getInputStream());\n                body = new byte[contentLength];\n                dataInputStream.readFully(body, 0, contentLength);\n            } catch (IOException e) {\n                return Response.newFixedLengthResponse(Status.INTERNAL_ERROR, NanoHTTPD.MIME_PLAINTEXT, e.getMessage());\n            }\n\n            String response = String.valueOf(method) + ':' + new String(body);\n            return Response.newFixedLengthResponse(response);\n        }\n    }\n\n    @Override\n    public TestServer createTestServer() {\n        return new TestServer();\n    }\n\n    @Test\n    public void testSimplePutRequest() throws Exception {\n        String expected = \"This HttpPut request has a content-length of 48.\";\n\n        HttpPut httpput = new HttpPut(\"http://localhost:8192/\");\n        httpput.setEntity(new ByteArrayEntity(expected.getBytes()));\n        ResponseHandler<String> responseHandler = new BasicResponseHandler();\n        String responseBody = this.httpclient.execute(httpput, responseHandler);\n\n        assertEquals(\"PUT:\" + expected, responseBody);\n    }\n}\n"
  },
  {
    "path": "core/src/test/java/org/nanohttpd/junit/protocols/http/integration/ShutdownTest.java",
    "content": "package org.nanohttpd.junit.protocols.http.integration;\n\n/*\n * #%L\n * NanoHttpd-Core\n * %%\n * Copyright (C) 2012 - 2015 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport static org.junit.Assert.fail;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.net.HttpURLConnection;\nimport java.net.MalformedURLException;\nimport java.net.URL;\n\nimport org.junit.Test;\nimport org.nanohttpd.protocols.http.IHTTPSession;\nimport org.nanohttpd.protocols.http.NanoHTTPD;\nimport org.nanohttpd.protocols.http.response.Response;\n\npublic class ShutdownTest {\n\n    private class TestServer extends NanoHTTPD {\n\n        public TestServer() {\n            super(8092);\n        }\n\n        @Override\n        public Response serve(IHTTPSession session) {\n            return Response.newFixedLengthResponse(\"Whatever\");\n        }\n    }\n\n    @Test\n    public void connectionsAreClosedWhenServerStops() throws IOException {\n        TestServer server = new TestServer();\n        server.start();\n        makeRequest();\n        server.stop();\n        try {\n            makeRequest();\n            fail(\"Connection should be closed!\");\n        } catch (IOException e) {\n            // Expected exception\n        }\n    }\n\n    private void makeRequest() throws MalformedURLException, IOException {\n        HttpURLConnection connection = (HttpURLConnection) new URL(\"http://localhost:8092/\").openConnection();\n        // Keep-alive seems to be on by default, but just in case that changes.\n        connection.addRequestProperty(\"Connection\", \"keep-alive\");\n        InputStream in = connection.getInputStream();\n        while (in.available() > 0) {\n            in.read();\n        }\n        in.close();\n    }\n\n}\n"
  },
  {
    "path": "core/src/test/resources/META-INF/nanohttpd/mimetypes.properties",
    "content": "#test mime types for nanohttpd\nblabla=text/blabla\nts=video/wrongOverwrite"
  },
  {
    "path": "core/src/test/resources/file-upload-test.htm",
    "content": "<!--\n  #%L\n  NanoHttpd-Core\n  %%\n  Copyright (C) 2012 - 2015 nanohttpd\n  %%\n  Redistribution and use in source and binary forms, with or without modification,\n  are permitted provided that the following conditions are met:\n  \n  1. Redistributions of source code must retain the above copyright notice, this\n     list of conditions and the following disclaimer.\n  \n  2. Redistributions in binary form must reproduce the above copyright notice,\n     this list of conditions and the following disclaimer in the documentation\n     and/or other materials provided with the distribution.\n  \n  3. Neither the name of the nanohttpd nor the names of its contributors\n     may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n  OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n  OF THE POSSIBILITY OF SUCH DAMAGE.\n  #L%\n  -->\n<html>\n <body>\n  <p>This is a file upload test for NanoHTTPD.</p>\n   <form action=\"http://localhost:8080/\" enctype=\"multipart/form-data\" method=\"post\">\n    <label for=\"textline\">Text:</label>\n       <input type=\"text\" id=\"textline\" name=\"textline\" size=\"30\"><br>\n    <label for=\"datafile1\">First File:</label>\n       <input type=\"file\" id=\"datafile1\" name=\"datafile1\" size=\"40\"><br>\n    <label for=\"datafile2\">Second File:</label>\n       <input type=\"file\" id=\"datafile2\" name=\"datafile2\" size=\"40\"><br>\n    <label for=\"datafile2\">Third File:</label>\n       <input type=\"file\" id=\"datafile3\" name=\"datafile3\" size=\"40\"><br>\n    <input type=\"submit\">\n   </form>\n </body>\n</html>\n"
  },
  {
    "path": "core/src/test/resources/multipart-form-test.htm",
    "content": "<!--\n  #%L\n  NanoHttpd-Core\n  %%\n  Copyright (C) 2012 - 2015 nanohttpd\n  %%\n  Redistribution and use in source and binary forms, with or without modification,\n  are permitted provided that the following conditions are met:\n  \n  1. Redistributions of source code must retain the above copyright notice, this\n     list of conditions and the following disclaimer.\n  \n  2. Redistributions in binary form must reproduce the above copyright notice,\n     this list of conditions and the following disclaimer in the documentation\n     and/or other materials provided with the distribution.\n  \n  3. Neither the name of the nanohttpd nor the names of its contributors\n     may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n  OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n  OF THE POSSIBILITY OF SUCH DAMAGE.\n  #L%\n  -->\n<html>\n <body>\n  <p>This is a multipart-form test for NanoHTTPD.</p>\n   <form action=\"http://localhost:8080/\" enctype=\"multipart/form-data\" method=\"post\">\n    <label for=\"textline\">Text:</label>\n       <input type=\"text\" id=\"textline\" name=\"textline\" size=\"30\"><br>\n    <label for=\"another\">Text:</label>\n       <input type=\"text\" id=\"another\" name=\"another\" size=\"30\"><br>\n    <label for=\"last\">Text:</label>\n       <input type=\"text\" id=\"last\" name=\"last\" size=\"30\"><br>\n    <input type=\"submit\">\n   </form>\n </body>\n</html>\n"
  },
  {
    "path": "fileupload/.gitignore",
    "content": "/.settings/\n/LICENSE.txt\n"
  },
  {
    "path": "fileupload/build.gradle",
    "content": "description = 'NanoHttpd-apache file upload integration'\n\ndependencies {\n\tcompile group: 'commons-fileupload', name: 'commons-fileupload', version: '1.3.1'\n\t\n\tcompileOnly project(':nanohttpd')\n\tcompileOnly group: 'javax.servlet', name: 'servlet-api', version: '2.5'\n\t\n\ttestCompile project(':nanohttpd')\n\ttestCompile group: 'javax.servlet', name: 'servlet-api', version: '2.5'\n\ttestCompile group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.4.1'\n\ttestCompile group: 'org.apache.httpcomponents', name: 'httpmime', version: '4.4.1'\n}\n\ntask wrapper(type: Wrapper) {\n\tgradleVersion = \"4.4.1\"\n}\n"
  },
  {
    "path": "fileupload/pom.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<parent>\n\t\t<artifactId>nanohttpd-project</artifactId>\n\t\t<groupId>org.nanohttpd</groupId>\n\t\t<version>2.3.2-SNAPSHOT</version>\n\t</parent>\n\t<modelVersion>4.0.0</modelVersion>\n\t<artifactId>nanohttpd-apache-fileupload</artifactId>\n\t<name>NanoHttpd-apache file upload integration</name>\n\t<description>nanohttpd-apache-fileupload integrates the apache file upload framework into nanohttpd</description>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.nanohttpd</groupId>\n\t\t\t<artifactId>nanohttpd</artifactId>\n\t\t\t<version>2.3.2-SNAPSHOT</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>commons-fileupload</groupId>\n\t\t\t<artifactId>commons-fileupload</artifactId>\n\t\t\t<version>1.3.1</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>javax.servlet</groupId>\n\t\t\t<artifactId>servlet-api</artifactId>\n\t\t\t<version>2.5</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.apache.httpcomponents</groupId>\n\t\t\t<artifactId>httpclient</artifactId>\n\t\t\t<version>4.4.1</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.apache.httpcomponents</groupId>\n\t\t\t<artifactId>httpmime</artifactId>\n\t\t\t<version>4.4.1</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t</dependencies>\n\t<properties>\n\t\t<minimal.coverage>0.99</minimal.coverage>\n\t</properties>\n</project>"
  },
  {
    "path": "fileupload/src/main/java/org/nanohttpd/fileupload/NanoFileUpload.java",
    "content": "package org.nanohttpd.fileupload;\n\n/*\n * #%L\n * NanoHttpd-apache file upload integration\n * %%\n * Copyright (C) 2012 - 2016 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.apache.commons.fileupload.FileItem;\nimport org.apache.commons.fileupload.FileItemFactory;\nimport org.apache.commons.fileupload.FileItemIterator;\nimport org.apache.commons.fileupload.FileUpload;\nimport org.apache.commons.fileupload.FileUploadBase;\nimport org.apache.commons.fileupload.FileUploadException;\nimport org.apache.commons.fileupload.UploadContext;\nimport org.nanohttpd.protocols.http.IHTTPSession;\nimport org.nanohttpd.protocols.http.request.Method;\n\n/**\n * @author victor & ritchieGitHub\n */\npublic class NanoFileUpload extends FileUpload {\n\n    public static class NanoHttpdContext implements UploadContext {\n\n        private IHTTPSession session;\n\n        public NanoHttpdContext(IHTTPSession session) {\n            this.session = session;\n        }\n\n        @Override\n        public long contentLength() {\n            long size;\n            try {\n                String cl1 = session.getHeaders().get(\"content-length\");\n                size = Long.parseLong(cl1);\n            } catch (NumberFormatException var4) {\n                size = -1L;\n            }\n\n            return size;\n        }\n\n        @Override\n        public String getCharacterEncoding() {\n            return \"UTF-8\";\n        }\n\n        @Override\n        public String getContentType() {\n            return this.session.getHeaders().get(\"content-type\");\n        }\n\n        @Override\n        public int getContentLength() {\n            return (int) contentLength();\n        }\n\n        @Override\n        public InputStream getInputStream() throws IOException {\n            return session.getInputStream();\n        }\n    }\n\n    public static final boolean isMultipartContent(IHTTPSession session) {\n        return session.getMethod() == Method.POST && FileUploadBase.isMultipartContent(new NanoHttpdContext(session));\n    }\n\n    public NanoFileUpload(FileItemFactory fileItemFactory) {\n        super(fileItemFactory);\n    }\n\n    public List<FileItem> parseRequest(IHTTPSession session) throws FileUploadException {\n        return this.parseRequest(new NanoHttpdContext(session));\n    }\n\n    public Map<String, List<FileItem>> parseParameterMap(IHTTPSession session) throws FileUploadException {\n        return this.parseParameterMap(new NanoHttpdContext(session));\n    }\n\n    public FileItemIterator getItemIterator(IHTTPSession session) throws FileUploadException, IOException {\n        return super.getItemIterator(new NanoHttpdContext(session));\n    }\n\n}\n"
  },
  {
    "path": "fileupload/src/test/java/org/nanohttpd/junit/fileupload/TestNanoFileUpLoad.java",
    "content": "package org.nanohttpd.junit.fileupload;\n\n/*\n * #%L\n * NanoHttpd-apache file upload integration\n * %%\n * Copyright (C) 2012 - 2015 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.net.InetAddress;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.apache.commons.fileupload.FileItem;\nimport org.apache.commons.fileupload.FileItemIterator;\nimport org.apache.commons.fileupload.FileItemStream;\nimport org.apache.commons.fileupload.disk.DiskFileItemFactory;\nimport org.apache.commons.fileupload.util.Streams;\nimport org.apache.http.HttpEntity;\nimport org.apache.http.HttpResponse;\nimport org.apache.http.client.ClientProtocolException;\nimport org.apache.http.client.methods.CloseableHttpResponse;\nimport org.apache.http.client.methods.HttpPost;\nimport org.apache.http.client.methods.HttpTrace;\nimport org.apache.http.entity.ContentType;\nimport org.apache.http.entity.mime.HttpMultipartMode;\nimport org.apache.http.entity.mime.MultipartEntityBuilder;\nimport org.apache.http.entity.mime.content.FileBody;\nimport org.apache.http.entity.mime.content.StringBody;\nimport org.apache.http.impl.client.CloseableHttpClient;\nimport org.apache.http.impl.client.HttpClients;\nimport org.junit.After;\nimport org.junit.Assert;\nimport org.junit.Before;\nimport org.junit.FixMethodOrder;\nimport org.junit.Test;\nimport org.nanohttpd.fileupload.NanoFileUpload;\nimport org.nanohttpd.protocols.http.HTTPSession;\nimport org.nanohttpd.protocols.http.IHTTPSession;\nimport org.nanohttpd.protocols.http.NanoHTTPD;\nimport org.nanohttpd.protocols.http.request.Method;\nimport org.nanohttpd.protocols.http.response.Response;\nimport org.nanohttpd.protocols.http.response.Status;\nimport org.nanohttpd.protocols.http.tempfiles.ITempFileManager;\n\n/**\n * very strange but if the file upload is the first request the test fails.\n * \n * @author ritchieGitHub\n */\n@FixMethodOrder\npublic class TestNanoFileUpLoad {\n\n    private static final String UPLOAD_JAVA_FILE = \"src/test/java/\" + TestNanoFileUpLoad.class.getName().replace('.', '/') + \".java\";\n\n    protected TestServer testServer;\n\n    public static class TestServer extends NanoHTTPD {\n\n        public Response response = Response.newFixedLengthResponse(\"\");\n\n        public String uri;\n\n        public Method method;\n\n        public Map<String, String> header;\n\n        public Map<String, String> parms;\n\n        public Map<String, List<FileItem>> files;\n\n        public Map<String, List<String>> decodedParamters;\n\n        public Map<String, List<String>> decodedParamtersFromParameter;\n\n        public String queryParameterString;\n\n        public TestServer() {\n            super(8192);\n            uploader = new NanoFileUpload(new DiskFileItemFactory());\n        }\n\n        public HTTPSession createSession(ITempFileManager tempFileManager, InputStream inputStream, OutputStream outputStream) {\n            return new HTTPSession(this, tempFileManager, inputStream, outputStream);\n        }\n\n        public HTTPSession createSession(ITempFileManager tempFileManager, InputStream inputStream, OutputStream outputStream, InetAddress inetAddress) {\n            return new HTTPSession(this, tempFileManager, inputStream, outputStream, inetAddress);\n        }\n\n        NanoFileUpload uploader;\n\n        @Override\n        public Response serve(IHTTPSession session) {\n\n            this.uri = session.getUri();\n            this.method = session.getMethod();\n            this.header = session.getHeaders();\n            this.parms = session.getParms();\n            if (NanoFileUpload.isMultipartContent(session)) {\n                try {\n                    if (\"/uploadFile1\".equals(this.uri)) {\n                        session.getHeaders().put(\"content-length\", \"AA\");\n                        files = uploader.parseParameterMap(session);\n                    }\n                    if (\"/uploadFile2\".equals(this.uri)) {\n                        files = new HashMap<String, List<FileItem>>();\n                        List<FileItem> parseRequest = uploader.parseRequest(session);\n                        files.put(parseRequest.get(0).getFieldName(), parseRequest);\n                    }\n                    if (\"/uploadFile3\".equals(this.uri)) {\n                        files = new HashMap<String, List<FileItem>>();\n                        FileItemIterator iter = uploader.getItemIterator(session);\n                        while (iter.hasNext()) {\n                            FileItemStream item = iter.next();\n                            final String fileName = item.getName();\n                            FileItem fileItem = uploader.getFileItemFactory().createItem(item.getFieldName(), item.getContentType(), item.isFormField(), fileName);\n                            files.put(fileItem.getFieldName(), Arrays.asList(new FileItem[]{\n                                fileItem\n                            }));\n                            try {\n                                Streams.copy(item.openStream(), fileItem.getOutputStream(), true);\n                            } catch (Exception e) {\n                            }\n                            fileItem.setHeaders(item.getHeaders());\n                        }\n                    }\n                } catch (Exception e) {\n                    this.response.setStatus(Status.INTERNAL_ERROR);\n                    e.printStackTrace();\n                }\n            }\n            this.queryParameterString = session.getQueryParameterString();\n            this.decodedParamtersFromParameter = decodeParameters(this.queryParameterString);\n            this.decodedParamters = decodeParameters(session.getQueryParameterString());\n            return this.response;\n        }\n\n    }\n\n    @Test\n    public void testNormalRequest() throws Exception {\n        CloseableHttpClient httpclient = HttpClients.createDefault();\n        HttpTrace httphead = new HttpTrace(\"http://localhost:8192/index.html\");\n        CloseableHttpResponse response = httpclient.execute(httphead);\n        Assert.assertEquals(200, response.getStatusLine().getStatusCode());\n        response.close();\n    }\n\n    @Test\n    public void testPostWithMultipartFormUpload1() throws Exception {\n        CloseableHttpClient httpclient = HttpClients.createDefault();\n        String textFileName = UPLOAD_JAVA_FILE;\n        HttpPost post = new HttpPost(\"http://localhost:8192/uploadFile1\");\n\n        executeUpload(httpclient, textFileName, post);\n        FileItem file = this.testServer.files.get(\"upfile\").get(0);\n        Assert.assertEquals(file.getSize(), new File(textFileName).length());\n    }\n\n    @Test\n    public void testPostWithMultipartFormUpload2() throws Exception {\n        CloseableHttpClient httpclient = HttpClients.createDefault();\n        String textFileName = UPLOAD_JAVA_FILE;\n        HttpPost post = new HttpPost(\"http://localhost:8192/uploadFile2\");\n\n        executeUpload(httpclient, textFileName, post);\n        FileItem file = this.testServer.files.get(\"upfile\").get(0);\n        Assert.assertEquals(file.getSize(), new File(textFileName).length());\n    }\n\n    @Test\n    public void testPostWithMultipartFormUpload3() throws Exception {\n        CloseableHttpClient httpclient = HttpClients.createDefault();\n        String textFileName = UPLOAD_JAVA_FILE;\n        HttpPost post = new HttpPost(\"http://localhost:8192/uploadFile3\");\n\n        executeUpload(httpclient, textFileName, post);\n        FileItem file = this.testServer.files.get(\"upfile\").get(0);\n        Assert.assertEquals(file.getSize(), new File(textFileName).length());\n    }\n\n    private void executeUpload(CloseableHttpClient httpclient, String textFileName, HttpPost post) throws IOException, ClientProtocolException {\n        FileBody fileBody = new FileBody(new File(textFileName), ContentType.DEFAULT_BINARY);\n        StringBody stringBody1 = new StringBody(\"Message 1\", ContentType.MULTIPART_FORM_DATA);\n\n        MultipartEntityBuilder builder = MultipartEntityBuilder.create();\n        builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);\n        builder.addPart(\"upfile\", fileBody);\n        builder.addPart(\"text1\", stringBody1);\n        HttpEntity entity = builder.build();\n        //\n        post.setEntity(entity);\n        HttpResponse response = httpclient.execute(post);\n        Assert.assertEquals(200, response.getStatusLine().getStatusCode());\n    }\n\n    @Before\n    public void setUp() throws IOException {\n        this.testServer = new TestServer();\n        this.testServer.start();\n        try {\n            long start = System.currentTimeMillis();\n            Thread.sleep(100L);\n            while (!this.testServer.wasStarted()) {\n                Thread.sleep(100L);\n                if (System.currentTimeMillis() - start > 2000) {\n                    Assert.fail(\"could not start server\");\n                }\n            }\n        } catch (InterruptedException e) {\n        }\n    }\n\n    @After\n    public void tearDown() {\n        this.testServer.stop();\n    }\n\n}\n"
  },
  {
    "path": "markdown-plugin/.gitignore",
    "content": "/.settings/\n/LICENSE.txt\n"
  },
  {
    "path": "markdown-plugin/build.gradle",
    "content": "description = 'NanoHttpd-Webserver-Markdown-Plugin'\n\ndependencies {\n\tcompile group: 'org.pegdown', name: 'pegdown', version: '1.4.1'\n\tcompileOnly project(':nanohttpd')\n\tcompileOnly project(':nanohttpd-webserver')\n}\n\ntask wrapper(type: Wrapper) {\n\tgradleVersion = \"4.4.1\"\n}\n"
  },
  {
    "path": "markdown-plugin/pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<parent>\n\t\t<groupId>org.nanohttpd</groupId>\n\t\t<artifactId>nanohttpd-project</artifactId>\n\t\t<version>2.3.2-SNAPSHOT</version>\n\t</parent>\n\t<artifactId>nanohttpd-webserver-markdown-plugin</artifactId>\n\t<packaging>jar</packaging>\n\t<name>NanoHttpd-Webserver-Markdown-Plugin</name>\n\t<url>https://github.com/NanoHttpd/nanohttpd</url>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>${project.groupId}</groupId>\n\t\t\t<artifactId>nanohttpd</artifactId>\n\t\t\t<version>${project.version}</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>${project.groupId}</groupId>\n\t\t\t<artifactId>nanohttpd-webserver</artifactId>\n\t\t\t<version>${project.version}</version>\n\t\t\t<scope>provided</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.pegdown</groupId>\n\t\t\t<artifactId>pegdown</artifactId>\n\t\t\t<version>1.4.1</version>\n\t\t</dependency>\n\t</dependencies>\n\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-assembly-plugin</artifactId>\n\t\t\t\t<version>2.2-beta-5</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<descriptorRefs>\n\t\t\t\t\t\t<descriptorRef>jar-with-dependencies</descriptorRef>\n\t\t\t\t\t</descriptorRefs>\n\t\t\t\t\t<archive>\n\t\t\t\t\t\t<manifest>\n\t\t\t\t\t\t\t<mainClass>fi.iki.elonen.SimpleWebServer</mainClass>\n\t\t\t\t\t\t</manifest>\n\t\t\t\t\t</archive>\n\t\t\t\t</configuration>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<phase>package</phase>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>single</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<properties>\n\t\t<minimal.coverage>0.0</minimal.coverage>\n\t</properties>\n</project>\n"
  },
  {
    "path": "markdown-plugin/src/main/java/org/nanohttpd/markdown/MarkdownWebServerPlugin.java",
    "content": "package org.nanohttpd.markdown;\n\n/*\n * #%L\n * NanoHttpd-Webserver-Markdown-Plugin\n * %%\n * Copyright (C) 2012 - 2016 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport java.io.BufferedReader;\nimport java.io.ByteArrayInputStream;\nimport java.io.File;\nimport java.io.FileReader;\nimport java.io.IOException;\nimport java.io.UnsupportedEncodingException;\nimport java.util.Map;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\nimport org.nanohttpd.protocols.http.IHTTPSession;\nimport org.nanohttpd.protocols.http.NanoHTTPD;\nimport org.nanohttpd.protocols.http.response.Response;\nimport org.nanohttpd.protocols.http.response.Status;\nimport org.nanohttpd.webserver.WebServerPlugin;\nimport org.pegdown.PegDownProcessor;\n\n/**\n * @author Paul S. Hawke (paul.hawke@gmail.com) On: 9/13/13 at 4:03 AM\n */\npublic class MarkdownWebServerPlugin implements WebServerPlugin {\n\n    /**\n     * logger to log to.\n     */\n    private static final Logger LOG = Logger.getLogger(MarkdownWebServerPlugin.class.getName());\n\n    private final PegDownProcessor processor;\n\n    public MarkdownWebServerPlugin() {\n        this.processor = new PegDownProcessor();\n    }\n\n    @Override\n    public boolean canServeUri(String uri, File rootDir) {\n        File f = new File(rootDir, uri);\n        return f.exists();\n    }\n\n    @Override\n    public void initialize(Map<String, String> commandLineOptions) {\n    }\n\n    private String readSource(File file) {\n        FileReader fileReader = null;\n        BufferedReader reader = null;\n        try {\n            fileReader = new FileReader(file);\n            reader = new BufferedReader(fileReader);\n            String line = null;\n            StringBuilder sb = new StringBuilder();\n            do {\n                line = reader.readLine();\n                if (line != null) {\n                    sb.append(line).append(\"\\n\");\n                }\n            } while (line != null);\n            reader.close();\n            return sb.toString();\n        } catch (Exception e) {\n            MarkdownWebServerPlugin.LOG.log(Level.SEVERE, \"could not read source\", e);\n            return null;\n        } finally {\n            try {\n                if (fileReader != null) {\n                    fileReader.close();\n                }\n                if (reader != null) {\n                    reader.close();\n                }\n            } catch (IOException ignored) {\n                MarkdownWebServerPlugin.LOG.log(Level.FINEST, \"close failed\", ignored);\n            }\n        }\n    }\n\n    @Override\n    public Response serveFile(String uri, Map<String, String> headers, IHTTPSession session, File file, String mimeType) {\n        String markdownSource = readSource(file);\n        byte[] bytes;\n        try {\n            bytes = this.processor.markdownToHtml(markdownSource).getBytes(\"UTF-8\");\n        } catch (UnsupportedEncodingException e) {\n            MarkdownWebServerPlugin.LOG.log(Level.SEVERE, \"encoding problem, responding nothing\", e);\n            bytes = new byte[0];\n        }\n        return markdownSource == null ? null : Response.newFixedLengthResponse(Status.OK, NanoHTTPD.MIME_HTML, new ByteArrayInputStream(bytes), bytes.length);\n    }\n}\n"
  },
  {
    "path": "markdown-plugin/src/main/java/org/nanohttpd/markdown/MarkdownWebServerPluginInfo.java",
    "content": "package org.nanohttpd.markdown;\n\nimport org.nanohttpd.webserver.WebServerPlugin;\nimport org.nanohttpd.webserver.WebServerPluginInfo;\n\n/*\n * #%L\n * NanoHttpd-Webserver-Markdown-Plugin\n * %%\n * Copyright (C) 2012 - 2015 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\n/**\n * @author Paul S. Hawke (paul.hawke@gmail.com) On: 9/13/13 at 4:01 AM\n */\npublic class MarkdownWebServerPluginInfo implements WebServerPluginInfo {\n\n    @Override\n    public String[] getIndexFilesForMimeType(String mime) {\n        return new String[]{\n            \"index.md\"\n        };\n    }\n\n    @Override\n    public String[] getMimeTypes() {\n        return new String[]{\n            \"text/markdown\"\n        };\n    }\n\n    @Override\n    public WebServerPlugin getWebServerPlugin(String mimeType) {\n        return new MarkdownWebServerPlugin();\n    }\n}\n"
  },
  {
    "path": "markdown-plugin/src/main/resources/META-INF/services/org.nanohttpd.webserver.WebServerPluginInfo",
    "content": "org.nanohttpd.markdown.MarkdownWebServerPluginInfo"
  },
  {
    "path": "markdown-plugin/src/site/site.xml",
    "content": "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n<project name=\"${project.name}\">\n\t<skin>\n\t\t<groupId>org.apache.maven.skins</groupId>\n\t\t<artifactId>maven-fluido-skin</artifactId>\n\t\t<version>1.3.0</version>\n\t</skin>\n\t<bannerLeft>\n\t\t<src>../images/nanohttpd_logo.png</src>\n\t</bannerLeft>\n\t<bannerRight>\n\t\t<src>../images/nanohttpd_logo_text.png</src>\n\t</bannerRight>\n\t<publishDate position=\"left\" format=\"yyyy-MM-dd\" />\n\t<version position=\"right\" />\n\t<poweredBy>\n\t\t<logo name=\"Maven\" href=\"http://maven.apache.org/\"\n\t\t\timg=\"http://maven.apache.org/images/logos/maven-feather.png\" />\n\t</poweredBy>\n\t<custom>\n\t\t<fluidoSkin>\n\t\t\t<topBarEnabled>false</topBarEnabled>\n\t\t\t<sideBarEnabled>true</sideBarEnabled>\n\t\t\t<gitHub>\n\t\t\t\t<projectId>Nanohttpd/nanohttpd</projectId>\n\t\t\t\t<ribbonOrientation>right</ribbonOrientation>\n\t\t\t\t<ribbonColor>black</ribbonColor>\n\t\t\t</gitHub>\n\t\t</fluidoSkin>\n\t</custom>\n\t<body>\n\t\t<breadcrumbs>\n\t\t\t<item name=\"${project.name}\" href=\"index.html\" />\n\t\t</breadcrumbs>\n\t\t<menu name=\"Documentation\">\n\t\t\t<item name=\"About\" href=\"index.html\" />\n\t\t</menu>\n\t\t<menu ref=\"modules\" />\n\t\t<menu ref=\"reports\" />\n\t</body>\n</project>"
  },
  {
    "path": "nanohttpd release perform.launch",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<launchConfiguration type=\"org.eclipse.m2e.Maven2LaunchConfigurationType\">\n<booleanAttribute key=\"M2_DEBUG_OUTPUT\" value=\"false\"/>\n<stringAttribute key=\"M2_GOALS\" value=\"release:perform\"/>\n<booleanAttribute key=\"M2_NON_RECURSIVE\" value=\"false\"/>\n<booleanAttribute key=\"M2_OFFLINE\" value=\"false\"/>\n<stringAttribute key=\"M2_PROFILES\" value=\"\"/>\n<listAttribute key=\"M2_PROPERTIES\"/>\n<stringAttribute key=\"M2_RUNTIME\" value=\"apache-maven-3.3.3\"/>\n<booleanAttribute key=\"M2_SKIP_TESTS\" value=\"false\"/>\n<intAttribute key=\"M2_THREADS\" value=\"1\"/>\n<booleanAttribute key=\"M2_UPDATE_SNAPSHOTS\" value=\"false\"/>\n<stringAttribute key=\"M2_USER_SETTINGS\" value=\"\"/>\n<booleanAttribute key=\"M2_WORKSPACE_RESOLUTION\" value=\"false\"/>\n<mapAttribute key=\"org.eclipse.debug.core.environmentVariables\">\n<mapEntry key=\"JAVA_HOME\" value=\"/home/nir/java/jdk1.7.0_79\"/>\n</mapAttribute>\n<stringAttribute key=\"org.eclipse.jdt.launching.VM_ARGUMENTS\" value=\"-Dmaven.multiModuleProjectDirectory=/home/nir/java/apache-maven-3.3.3\"/>\n<stringAttribute key=\"org.eclipse.jdt.launching.WORKING_DIRECTORY\" value=\"${workspace_loc:/nanohttpd}\"/>\n</launchConfiguration>\n"
  },
  {
    "path": "nanohttpd release prepare.launch",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n<launchConfiguration type=\"org.eclipse.m2e.Maven2LaunchConfigurationType\">\n<booleanAttribute key=\"M2_DEBUG_OUTPUT\" value=\"false\"/>\n<stringAttribute key=\"M2_GOALS\" value=\"release:prepare\"/>\n<booleanAttribute key=\"M2_NON_RECURSIVE\" value=\"false\"/>\n<booleanAttribute key=\"M2_OFFLINE\" value=\"false\"/>\n<stringAttribute key=\"M2_PROFILES\" value=\"\"/>\n<listAttribute key=\"M2_PROPERTIES\"/>\n<stringAttribute key=\"M2_RUNTIME\" value=\"apache-maven-3.3.3\"/>\n<booleanAttribute key=\"M2_SKIP_TESTS\" value=\"false\"/>\n<intAttribute key=\"M2_THREADS\" value=\"1\"/>\n<booleanAttribute key=\"M2_UPDATE_SNAPSHOTS\" value=\"false\"/>\n<stringAttribute key=\"M2_USER_SETTINGS\" value=\"\"/>\n<booleanAttribute key=\"M2_WORKSPACE_RESOLUTION\" value=\"false\"/>\n<mapAttribute key=\"org.eclipse.debug.core.environmentVariables\">\n<mapEntry key=\"JAVA_HOME\" value=\"/home/nir/java/jdk1.7.0_79\"/>\n</mapAttribute>\n<stringAttribute key=\"org.eclipse.jdt.launching.VM_ARGUMENTS\" value=\"-Dmaven.multiModuleProjectDirectory=/home/nir/java/apache-maven-3.3.3\"/>\n<stringAttribute key=\"org.eclipse.jdt.launching.WORKING_DIRECTORY\" value=\"${workspace_loc:/nanohttpd}\"/>\n</launchConfiguration>\n"
  },
  {
    "path": "nanolets/.gitignore",
    "content": "/.settings/\n/LICENSE.txt\n"
  },
  {
    "path": "nanolets/build.gradle",
    "content": "description = 'NanoHttpd-nano application server'\n\ndependencies {\n\tcompile project(':nanohttpd')\n\t\n\ttestCompile group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.4.1'\n}\n"
  },
  {
    "path": "nanolets/pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<parent>\n\t\t<groupId>org.nanohttpd</groupId>\n\t\t<artifactId>nanohttpd-project</artifactId>\n\t\t<version>2.3.2-SNAPSHOT</version>\n\t</parent>\n\t<artifactId>nanohttpd-nanolets</artifactId>\n\t<packaging>jar</packaging>\n\t<name>NanoHttpd-nano application server</name>\n\t<description>nanohttpd-nanolets add a very easy to use version of servlets into nanohttpd.</description>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>${project.groupId}</groupId>\n\t\t\t<artifactId>nanohttpd</artifactId>\n\t\t\t<version>${project.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.apache.httpcomponents</groupId>\n\t\t\t<artifactId>httpclient</artifactId>\n\t\t\t<version>4.4.1</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t</dependencies>\n\t<properties>\n\t\t<minimal.coverage>0.96</minimal.coverage>\n\t</properties>\n</project>\n"
  },
  {
    "path": "nanolets/src/main/java/org/nanohttpd/router/RouterNanoHTTPD.java",
    "content": "package org.nanohttpd.router;\n\n/*\n * #%L\n * NanoHttpd-Samples\n * %%\n * Copyright (C) 2012 - 2015 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport java.io.BufferedInputStream;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.PriorityQueue;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport org.nanohttpd.protocols.http.IHTTPSession;\nimport org.nanohttpd.protocols.http.NanoHTTPD;\nimport org.nanohttpd.protocols.http.response.IStatus;\nimport org.nanohttpd.protocols.http.response.Response;\nimport org.nanohttpd.protocols.http.response.Status;\n\n/**\n * @author vnnv\n * @author ritchieGitHub\n */\npublic class RouterNanoHTTPD extends NanoHTTPD {\n\n    /**\n     * logger to log to.\n     */\n    private static final Logger LOG = Logger.getLogger(RouterNanoHTTPD.class.getName());\n\n    public interface UriResponder {\n\n        public Response get(UriResource uriResource, Map<String, String> urlParams, IHTTPSession session);\n\n        public Response put(UriResource uriResource, Map<String, String> urlParams, IHTTPSession session);\n\n        public Response post(UriResource uriResource, Map<String, String> urlParams, IHTTPSession session);\n\n        public Response delete(UriResource uriResource, Map<String, String> urlParams, IHTTPSession session);\n\n        public Response other(String method, UriResource uriResource, Map<String, String> urlParams, IHTTPSession session);\n    }\n\n    /**\n     * General nanolet to inherit from if you provide stream data, only chucked\n     * responses will be generated.\n     */\n    public static abstract class DefaultStreamHandler implements UriResponder {\n\n        public abstract String getMimeType();\n\n        public abstract IStatus getStatus();\n\n        public abstract InputStream getData();\n\n        public Response get(UriResource uriResource, Map<String, String> urlParams, IHTTPSession session) {\n            return Response.newChunkedResponse(getStatus(), getMimeType(), getData());\n        }\n\n        public Response post(UriResource uriResource, Map<String, String> urlParams, IHTTPSession session) {\n            return get(uriResource, urlParams, session);\n        }\n\n        public Response put(UriResource uriResource, Map<String, String> urlParams, IHTTPSession session) {\n            return get(uriResource, urlParams, session);\n        }\n\n        public Response delete(UriResource uriResource, Map<String, String> urlParams, IHTTPSession session) {\n            return get(uriResource, urlParams, session);\n        }\n\n        public Response other(String method, UriResource uriResource, Map<String, String> urlParams, IHTTPSession session) {\n            return get(uriResource, urlParams, session);\n        }\n    }\n\n    /**\n     * General nanolet to inherit from if you provide text or html data, only\n     * fixed size responses will be generated.\n     */\n    public static abstract class DefaultHandler extends DefaultStreamHandler {\n\n        public abstract String getText();\n\n        public abstract IStatus getStatus();\n\n        public Response get(UriResource uriResource, Map<String, String> urlParams, IHTTPSession session) {\n            return Response.newFixedLengthResponse(getStatus(), getMimeType(), getText());\n        }\n\n        @Override\n        public InputStream getData() {\n            throw new IllegalStateException(\"this method should not be called in a text based nanolet\");\n        }\n    }\n\n    /**\n     * General nanolet to print debug info's as a html page.\n     */\n    public static class GeneralHandler extends DefaultHandler {\n\n        @Override\n        public String getText() {\n            throw new IllegalStateException(\"this method should not be called\");\n        }\n\n        @Override\n        public String getMimeType() {\n            return \"text/html\";\n        }\n\n        @Override\n        public IStatus getStatus() {\n            return Status.OK;\n        }\n\n        public Response get(UriResource uriResource, Map<String, String> urlParams, IHTTPSession session) {\n            StringBuilder text = new StringBuilder(\"<html><body>\");\n            text.append(\"<h1>Url: \");\n            text.append(session.getUri());\n            text.append(\"</h1><br>\");\n            Map<String, String> queryParams = session.getParms();\n            if (queryParams.size() > 0) {\n                for (Map.Entry<String, String> entry : queryParams.entrySet()) {\n                    String key = entry.getKey();\n                    String value = entry.getValue();\n                    text.append(\"<p>Param '\");\n                    text.append(key);\n                    text.append(\"' = \");\n                    text.append(value);\n                    text.append(\"</p>\");\n                }\n            } else {\n                text.append(\"<p>no params in url</p><br>\");\n            }\n            return Response.newFixedLengthResponse(getStatus(), getMimeType(), text.toString());\n        }\n    }\n\n    /**\n     * General nanolet to print debug info's as a html page.\n     */\n    public static class StaticPageHandler extends DefaultHandler {\n\n        private static String[] getPathArray(String uri) {\n            String array[] = uri.split(\"/\");\n            ArrayList<String> pathArray = new ArrayList<String>();\n\n            for (String s : array) {\n                if (s.length() > 0)\n                    pathArray.add(s);\n            }\n\n            return pathArray.toArray(new String[]{});\n\n        }\n\n        @Override\n        public String getText() {\n            throw new IllegalStateException(\"this method should not be called\");\n        }\n\n        @Override\n        public String getMimeType() {\n            throw new IllegalStateException(\"this method should not be called\");\n        }\n\n        @Override\n        public IStatus getStatus() {\n            return Status.OK;\n        }\n\n        public Response get(UriResource uriResource, Map<String, String> urlParams, IHTTPSession session) {\n            String baseUri = uriResource.getUri();\n            String realUri = normalizeUri(session.getUri());\n            for (int index = 0; index < Math.min(baseUri.length(), realUri.length()); index++) {\n                if (baseUri.charAt(index) != realUri.charAt(index)) {\n                    realUri = normalizeUri(realUri.substring(index));\n                    break;\n                }\n            }\n            File fileOrdirectory = uriResource.initParameter(File.class);\n            for (String pathPart : getPathArray(realUri)) {\n                fileOrdirectory = new File(fileOrdirectory, pathPart);\n            }\n            if (fileOrdirectory.isDirectory()) {\n                fileOrdirectory = new File(fileOrdirectory, \"index.html\");\n                if (!fileOrdirectory.exists()) {\n                    fileOrdirectory = new File(fileOrdirectory.getParentFile(), \"index.htm\");\n                }\n            }\n            if (!fileOrdirectory.exists() || !fileOrdirectory.isFile()) {\n                return new Error404UriHandler().get(uriResource, urlParams, session);\n            } else {\n                try {\n                    return Response.newChunkedResponse(getStatus(), getMimeTypeForFile(fileOrdirectory.getName()), fileToInputStream(fileOrdirectory));\n                } catch (IOException ioe) {\n                    return Response.newFixedLengthResponse(Status.REQUEST_TIMEOUT, \"text/plain\", (String) null);\n                }\n            }\n        }\n\n        protected BufferedInputStream fileToInputStream(File fileOrdirectory) throws IOException {\n            return new BufferedInputStream(new FileInputStream(fileOrdirectory));\n        }\n    }\n\n    /**\n     * Handling error 404 - unrecognized urls\n     */\n    public static class Error404UriHandler extends DefaultHandler {\n\n        public String getText() {\n            return \"<html><body><h3>Error 404: the requested page doesn't exist.</h3></body></html>\";\n        }\n\n        @Override\n        public String getMimeType() {\n            return \"text/html\";\n        }\n\n        @Override\n        public IStatus getStatus() {\n            return Status.NOT_FOUND;\n        }\n    }\n\n    /**\n     * Handling index\n     */\n    public static class IndexHandler extends DefaultHandler {\n\n        public String getText() {\n            return \"<html><body><h2>Hello world!</h3></body></html>\";\n        }\n\n        @Override\n        public String getMimeType() {\n            return \"text/html\";\n        }\n\n        @Override\n        public IStatus getStatus() {\n            return Status.OK;\n        }\n\n    }\n\n    public static class NotImplementedHandler extends DefaultHandler {\n\n        public String getText() {\n            return \"<html><body><h2>The uri is mapped in the router, but no handler is specified. <br> Status: Not implemented!</h3></body></html>\";\n        }\n\n        @Override\n        public String getMimeType() {\n            return \"text/html\";\n        }\n\n        @Override\n        public IStatus getStatus() {\n            return Status.OK;\n        }\n    }\n\n    public static String normalizeUri(String value) {\n        if (value == null) {\n            return value;\n        }\n        if (value.startsWith(\"/\")) {\n            value = value.substring(1);\n        }\n        if (value.endsWith(\"/\")) {\n            value = value.substring(0, value.length() - 1);\n        }\n        return value;\n\n    }\n\n    public static class UriResource implements Comparable<UriResource> {\n\n        private static final Pattern PARAM_PATTERN = Pattern.compile(\"(?<=(^|/)):[a-zA-Z0-9_-]+(?=(/|$))\");\n\n        private static final String PARAM_MATCHER = \"([A-Za-z0-9\\\\-\\\\._~:/?#\\\\[\\\\]@!\\\\$&'\\\\(\\\\)\\\\*\\\\+,;=\\\\s]+)\";\n\n        private static final Map<String, String> EMPTY = Collections.unmodifiableMap(new HashMap<String, String>());\n\n        private final String uri;\n\n        private final Pattern uriPattern;\n\n        private int priority;\n\n        private final Class<?> handler;\n\n        private final Object[] initParameter;\n\n        private final List<String> uriParams = new ArrayList<String>();\n\n        public UriResource(String uri, int priority, Class<?> handler, Object... initParameter) {\n            this(uri, handler, initParameter);\n            this.priority = priority + uriParams.size() * 1000;\n        }\n\n        public UriResource(String uri, Class<?> handler, Object... initParameter) {\n            this.handler = handler;\n            this.initParameter = initParameter;\n            if (uri != null) {\n                this.uri = normalizeUri(uri);\n                parse();\n                this.uriPattern = createUriPattern();\n            } else {\n                this.uriPattern = null;\n                this.uri = null;\n            }\n        }\n\n        private void parse() {\n        }\n\n        private Pattern createUriPattern() {\n            String patternUri = uri;\n            Matcher matcher = PARAM_PATTERN.matcher(patternUri);\n            int start = 0;\n            while (matcher.find(start)) {\n                uriParams.add(patternUri.substring(matcher.start() + 1, matcher.end()));\n                patternUri = new StringBuilder(patternUri.substring(0, matcher.start()))//\n                        .append(PARAM_MATCHER)//\n                        .append(patternUri.substring(matcher.end())).toString();\n                start = matcher.start() + PARAM_MATCHER.length();\n                matcher = PARAM_PATTERN.matcher(patternUri);\n            }\n            return Pattern.compile(patternUri);\n        }\n\n        public Response process(Map<String, String> urlParams, IHTTPSession session) {\n            String error = \"General error!\";\n            if (handler != null) {\n                try {\n                    Object object = handler.newInstance();\n                    if (object instanceof UriResponder) {\n                        UriResponder responder = (UriResponder) object;\n                        switch (session.getMethod()) {\n                            case GET:\n                                return responder.get(this, urlParams, session);\n                            case POST:\n                                return responder.post(this, urlParams, session);\n                            case PUT:\n                                return responder.put(this, urlParams, session);\n                            case DELETE:\n                                return responder.delete(this, urlParams, session);\n                            default:\n                                return responder.other(session.getMethod().toString(), this, urlParams, session);\n                        }\n                    } else {\n                        return Response.newFixedLengthResponse(Status.OK, \"text/plain\", //\n                                new StringBuilder(\"Return: \")//\n                                        .append(handler.getCanonicalName())//\n                                        .append(\".toString() -> \")//\n                                        .append(object)//\n                                        .toString());\n                    }\n                } catch (Exception e) {\n                    error = \"Error: \" + e.getClass().getName() + \" : \" + e.getMessage();\n                    LOG.log(Level.SEVERE, error, e);\n                }\n            }\n            return Response.newFixedLengthResponse(Status.INTERNAL_ERROR, \"text/plain\", error);\n        }\n\n        @Override\n        public String toString() {\n            return new StringBuilder(\"UrlResource{uri='\").append((uri == null ? \"/\" : uri))//\n                    .append(\"', urlParts=\").append(uriParams)//\n                    .append('}')//\n                    .toString();\n        }\n\n        public String getUri() {\n            return uri;\n        }\n\n        public <T> T initParameter(Class<T> paramClazz) {\n            return initParameter(0, paramClazz);\n        }\n\n        public <T> T initParameter(int parameterIndex, Class<T> paramClazz) {\n            if (initParameter.length > parameterIndex) {\n                return paramClazz.cast(initParameter[parameterIndex]);\n            }\n            LOG.severe(\"init parameter index not available \" + parameterIndex);\n            return null;\n        }\n\n        public Map<String, String> match(String url) {\n            Matcher matcher = uriPattern.matcher(url);\n            if (matcher.matches()) {\n                if (uriParams.size() > 0) {\n                    Map<String, String> result = new HashMap<String, String>();\n                    for (int i = 1; i <= matcher.groupCount(); i++) {\n                        result.put(uriParams.get(i - 1), matcher.group(i));\n                    }\n                    return result;\n                } else {\n                    return EMPTY;\n                }\n            }\n            return null;\n        }\n\n        @Override\n        public int compareTo(UriResource that) {\n            if (that == null) {\n                return 1;\n            } else if (this.priority > that.priority) {\n                return 1;\n            } else if (this.priority < that.priority) {\n                return -1;\n            } else {\n                return 0;\n            }\n        }\n\n        public void setPriority(int priority) {\n            this.priority = priority;\n        }\n\n    }\n\n    public static interface IRoutePrioritizer {\n\n        void addRoute(String url, int priority, Class<?> handler, Object... initParameter);\n\n        void removeRoute(String url);\n\n        Collection<UriResource> getPrioritizedRoutes();\n\n        void setNotImplemented(Class<?> notImplemented);\n    }\n\n    public static abstract class BaseRoutePrioritizer implements IRoutePrioritizer {\n\n        protected Class<?> notImplemented;\n\n        protected final Collection<UriResource> mappings;\n\n        public BaseRoutePrioritizer() {\n            this.mappings = newMappingCollection();\n            this.notImplemented = NotImplementedHandler.class;\n        }\n\n        @Override\n        public void addRoute(String url, int priority, Class<?> handler, Object... initParameter) {\n            if (url != null) {\n                if (handler != null) {\n                    mappings.add(new UriResource(url, priority + mappings.size(), handler, initParameter));\n                } else {\n                    mappings.add(new UriResource(url, priority + mappings.size(), notImplemented));\n                }\n            }\n        }\n\n        public void removeRoute(String url) {\n            String uriToDelete = normalizeUri(url);\n            Iterator<UriResource> iter = mappings.iterator();\n            while (iter.hasNext()) {\n                UriResource uriResource = iter.next();\n                if (uriToDelete.equals(uriResource.getUri())) {\n                    iter.remove();\n                    break;\n                }\n            }\n        }\n\n        @Override\n        public Collection<UriResource> getPrioritizedRoutes() {\n            return Collections.unmodifiableCollection(mappings);\n        }\n\n        @Override\n        public void setNotImplemented(Class<?> handler) {\n            notImplemented = handler;\n        }\n\n        protected abstract Collection<UriResource> newMappingCollection();\n    }\n\n    public static class ProvidedPriorityRoutePrioritizer extends BaseRoutePrioritizer {\n\n        @Override\n        public void addRoute(String url, int priority, Class<?> handler, Object... initParameter) {\n            if (url != null) {\n                UriResource resource = null;\n                if (handler != null) {\n                    resource = new UriResource(url, handler, initParameter);\n                } else {\n                    resource = new UriResource(url, handler, notImplemented);\n                }\n\n                resource.setPriority(priority);\n                mappings.add(resource);\n            }\n        }\n\n        @Override\n        protected Collection<UriResource> newMappingCollection() {\n            return new PriorityQueue<UriResource>();\n        }\n\n    }\n\n    public static class DefaultRoutePrioritizer extends BaseRoutePrioritizer {\n\n        protected Collection<UriResource> newMappingCollection() {\n            return new PriorityQueue<UriResource>();\n        }\n    }\n\n    public static class InsertionOrderRoutePrioritizer extends BaseRoutePrioritizer {\n\n        protected Collection<UriResource> newMappingCollection() {\n            return new ArrayList<UriResource>();\n        }\n    }\n\n    public static class UriRouter {\n\n        private UriResource error404Url;\n\n        private IRoutePrioritizer routePrioritizer;\n\n        public UriRouter() {\n            this.routePrioritizer = new DefaultRoutePrioritizer();\n        }\n\n        /**\n         * Search in the mappings if the given url matches some of the rules If\n         * there are more than one marches returns the rule with less parameters\n         * e.g. mapping 1 = /user/:id mapping 2 = /user/help if the incoming uri\n         * is www.example.com/user/help - mapping 2 is returned if the incoming\n         * uri is www.example.com/user/3232 - mapping 1 is returned\n         * \n         * @param url\n         * @return\n         */\n        public Response process(IHTTPSession session) {\n            String work = normalizeUri(session.getUri());\n            Map<String, String> params = null;\n            UriResource uriResource = error404Url;\n            for (UriResource u : routePrioritizer.getPrioritizedRoutes()) {\n                params = u.match(work);\n                if (params != null) {\n                    uriResource = u;\n                    break;\n                }\n            }\n            return uriResource.process(params, session);\n        }\n\n        private void addRoute(String url, int priority, Class<?> handler, Object... initParameter) {\n            routePrioritizer.addRoute(url, priority, handler, initParameter);\n        }\n\n        private void removeRoute(String url) {\n            routePrioritizer.removeRoute(url);\n        }\n\n        public void setNotFoundHandler(Class<?> handler) {\n            error404Url = new UriResource(null, 100, handler);\n        }\n\n        public void setNotImplemented(Class<?> handler) {\n            routePrioritizer.setNotImplemented(handler);\n        }\n\n        public void setRoutePrioritizer(IRoutePrioritizer routePrioritizer) {\n            this.routePrioritizer = routePrioritizer;\n        }\n\n    }\n\n    private UriRouter router;\n\n    public RouterNanoHTTPD(int port) {\n        super(port);\n        router = new UriRouter();\n    }\n\n    public RouterNanoHTTPD(String hostname, int port) {\n        super(hostname, port);\n        router = new UriRouter();\n    }\n\n    /**\n     * default routings, they are over writable.\n     * \n     * <pre>\n     * router.setNotFoundHandler(GeneralHandler.class);\n     * </pre>\n     */\n\n    public void addMappings() {\n        router.setNotImplemented(NotImplementedHandler.class);\n        router.setNotFoundHandler(Error404UriHandler.class);\n        router.addRoute(\"/\", Integer.MAX_VALUE / 2, IndexHandler.class);\n        router.addRoute(\"/index.html\", Integer.MAX_VALUE / 2, IndexHandler.class);\n    }\n\n    public void addRoute(String url, Class<?> handler, Object... initParameter) {\n        router.addRoute(url, 100, handler, initParameter);\n    }\n\n    public <T extends UriResponder> void setNotImplementedHandler(Class<T> handler) {\n        router.setNotImplemented(handler);\n    }\n\n    public <T extends UriResponder> void setNotFoundHandler(Class<T> handler) {\n        router.setNotFoundHandler(handler);\n    }\n\n    public void removeRoute(String url) {\n        router.removeRoute(url);\n    }\n\n    public void setRoutePrioritizer(IRoutePrioritizer routePrioritizer) {\n        router.setRoutePrioritizer(routePrioritizer);\n    }\n\n    @Override\n    public Response serve(IHTTPSession session) {\n        // Try to find match\n        return router.process(session);\n    }\n}\n"
  },
  {
    "path": "nanolets/src/test/java/org/nanohttpd/junit/router/AppNanolets.java",
    "content": "package org.nanohttpd.junit.router;\n\n/*\n * #%L\n * NanoHttpd-Samples\n * %%\n * Copyright (C) 2012 - 2015 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\n/**\n * Created by vnnv on 7/17/15.\n * Simple httpd server based on NanoHTTPD\n * Read the source. Everything is there.\n */\n\nimport java.io.BufferedInputStream;\nimport java.io.ByteArrayInputStream;\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.Map;\n\nimport org.nanohttpd.protocols.http.IHTTPSession;\nimport org.nanohttpd.protocols.http.response.IStatus;\nimport org.nanohttpd.protocols.http.response.Response;\nimport org.nanohttpd.protocols.http.response.Status;\nimport org.nanohttpd.router.RouterNanoHTTPD;\nimport org.nanohttpd.router.RouterNanoHTTPD.DefaultHandler;\nimport org.nanohttpd.router.RouterNanoHTTPD.DefaultStreamHandler;\nimport org.nanohttpd.router.RouterNanoHTTPD.GeneralHandler;\nimport org.nanohttpd.router.RouterNanoHTTPD.StaticPageHandler;\nimport org.nanohttpd.router.RouterNanoHTTPD.UriResource;\nimport org.nanohttpd.router.RouterNanoHTTPD.UriResponder;\nimport org.nanohttpd.util.ServerRunner;\n\npublic class AppNanolets extends RouterNanoHTTPD {\n\n    private static final int PORT = 9090;\n\n    public static class UserHandler extends DefaultHandler {\n\n        @Override\n        public String getText() {\n            return \"not implemented\";\n        }\n\n        public String getText(Map<String, String> urlParams, IHTTPSession session) {\n            String text = \"<html><body>User handler. Method: \" + session.getMethod().toString() + \"<br>\";\n            text += \"<h1>Uri parameters:</h1>\";\n            for (Map.Entry<String, String> entry : urlParams.entrySet()) {\n                String key = entry.getKey();\n                String value = entry.getValue();\n                text += \"<div> Param: \" + key + \"&nbsp;Value: \" + value + \"</div>\";\n            }\n            text += \"<h1>Query parameters:</h1>\";\n            for (Map.Entry<String, String> entry : session.getParms().entrySet()) {\n                String key = entry.getKey();\n                String value = entry.getValue();\n                text += \"<div> Query Param: \" + key + \"&nbsp;Value: \" + value + \"</div>\";\n            }\n            text += \"</body></html>\";\n\n            return text;\n        }\n\n        @Override\n        public String getMimeType() {\n            return \"text/html\";\n        }\n\n        @Override\n        public IStatus getStatus() {\n            return Status.OK;\n        }\n\n        public Response get(UriResource uriResource, Map<String, String> urlParams, IHTTPSession session) {\n            String text = getText(urlParams, session);\n            ByteArrayInputStream inp = new ByteArrayInputStream(text.getBytes());\n            int size = text.getBytes().length;\n            return Response.newFixedLengthResponse(getStatus(), getMimeType(), inp, size);\n        }\n\n    }\n\n    static public class StreamUrl extends DefaultStreamHandler {\n\n        @Override\n        public String getMimeType() {\n            return \"text/plain\";\n        }\n\n        @Override\n        public IStatus getStatus() {\n            return Status.OK;\n        }\n\n        @Override\n        public InputStream getData() {\n            return new ByteArrayInputStream(\"a stream of data ;-)\".getBytes());\n        }\n\n    }\n\n    public static class StaticPageTestHandler extends StaticPageHandler {\n\n        @Override\n        protected BufferedInputStream fileToInputStream(File fileOrdirectory) throws IOException {\n            if (\"exception.html\".equals(fileOrdirectory.getName())) {\n                throw new IOException(\"trigger something wrong\");\n            }\n            return super.fileToInputStream(fileOrdirectory);\n        }\n    }\n\n    /**\n     * Create the server instance\n     */\n    public AppNanolets() throws IOException {\n        super(PORT);\n        addMappings();\n        System.out.println(\"\\nRunning! Point your browers to http://localhost:\" + PORT + \"/ \\n\");\n    }\n\n    /**\n     * Add the routes Every route is an absolute path Parameters starts with \":\"\n     * Handler class should implement @UriResponder interface If the handler not\n     * implement UriResponder interface - toString() is used\n     */\n    @Override\n    public void addMappings() {\n        super.addMappings();\n        addRoute(\"/user\", UserHandler.class);\n        addRoute(\"/user\", UserHandler.class); // add it twice to execute the\n                                              // priority == priority case\n        addRoute(\"/user/help\", GeneralHandler.class);\n        addRoute(\"/user/:id\", UserHandler.class);\n        addRoute(\"/general/:param1/:param2\", GeneralHandler.class);\n        addRoute(\"/photos/:customer_id/:photo_id\", null);\n        addRoute(\"/test\", String.class);\n        addRoute(\"/interface\", UriResponder.class); // this will cause an error\n                                                    // when called\n        addRoute(\"/toBeDeleted\", String.class);\n        removeRoute(\"/toBeDeleted\");\n        addRoute(\"/stream\", StreamUrl.class);\n        addRoute(\"/browse/(.)+\", StaticPageTestHandler.class, new File(\"src/test/resources\").getAbsoluteFile());\n    }\n\n    /**\n     * Main entry point\n     * \n     * @param args\n     */\n    public static void main(String[] args) {\n        ServerRunner.run(AppNanolets.class);\n    }\n}\n"
  },
  {
    "path": "nanolets/src/test/java/org/nanohttpd/junit/router/TestNanolets.java",
    "content": "package org.nanohttpd.junit.router;\n\n/*\n * #%L\n * NanoHttpd nano application server\n * %%\n * Copyright (C) 2012 - 2015 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.PipedInputStream;\nimport java.io.PipedOutputStream;\nimport java.lang.reflect.Field;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport org.apache.http.HttpEntity;\nimport org.apache.http.client.ClientProtocolException;\nimport org.apache.http.client.methods.CloseableHttpResponse;\nimport org.apache.http.client.methods.HttpDelete;\nimport org.apache.http.client.methods.HttpGet;\nimport org.apache.http.client.methods.HttpPost;\nimport org.apache.http.client.methods.HttpPut;\nimport org.apache.http.client.methods.HttpTrace;\nimport org.apache.http.impl.client.CloseableHttpClient;\nimport org.apache.http.impl.client.HttpClients;\nimport org.junit.AfterClass;\nimport org.junit.Assert;\nimport org.junit.BeforeClass;\nimport org.junit.Test;\nimport org.nanohttpd.protocols.http.response.Status;\nimport org.nanohttpd.router.RouterNanoHTTPD;\nimport org.nanohttpd.router.RouterNanoHTTPD.DefaultRoutePrioritizer;\nimport org.nanohttpd.router.RouterNanoHTTPD.Error404UriHandler;\nimport org.nanohttpd.router.RouterNanoHTTPD.GeneralHandler;\nimport org.nanohttpd.router.RouterNanoHTTPD.IndexHandler;\nimport org.nanohttpd.router.RouterNanoHTTPD.InsertionOrderRoutePrioritizer;\nimport org.nanohttpd.router.RouterNanoHTTPD.NotImplementedHandler;\nimport org.nanohttpd.router.RouterNanoHTTPD.ProvidedPriorityRoutePrioritizer;\nimport org.nanohttpd.router.RouterNanoHTTPD.StaticPageHandler;\nimport org.nanohttpd.router.RouterNanoHTTPD.UriResource;\nimport org.nanohttpd.router.RouterNanoHTTPD.UriResponder;\nimport org.nanohttpd.router.RouterNanoHTTPD.UriRouter;\n\npublic class TestNanolets {\n\n    private static PipedOutputStream stdIn;\n\n    private static Thread serverStartThread;\n\n    @BeforeClass\n    public static void setUp() throws Exception {\n        stdIn = new PipedOutputStream();\n        System.setIn(new PipedInputStream(stdIn));\n        serverStartThread = new Thread(new Runnable() {\n\n            @Override\n            public void run() {\n                String[] args = {};\n                AppNanolets.main(args);\n            }\n        });\n        serverStartThread.start();\n        // give the server some tine to start.\n        Thread.sleep(200);\n    }\n\n    public static void main(String[] args) {\n        {\n            String uri = \"def\";\n            Pattern.compile(\"([A-Za-z0-9\\\\-\\\\._~:/?#\\\\[\\\\]@!\\\\$&'\\\\(\\\\)\\\\*\\\\+,;=]+)\");\n            Pattern URI_PATTERN = Pattern.compile(\"([A-Za-z0-9\\\\-\\\\._~:/?#\\\\[\\\\]@!\\\\$&'\\\\(\\\\)\\\\*\\\\+,;=]+)\");\n            System.out.println(URI_PATTERN.matcher(uri).matches());\n        }\n\n        String uri = \"photos/abc/def\";\n        Pattern URI_PATTERN = Pattern.compile(\"photos/([A-Za-z0-9\\\\-\\\\._~:/?#\\\\[\\\\]@!\\\\$&'\\\\(\\\\)\\\\*\\\\+,;=]+)/([A-Za-z0-9\\\\-\\\\._~:/?#\\\\[\\\\]@!\\\\$&'\\\\(\\\\)\\\\*\\\\+,;=]+)\");\n        Matcher matcher = URI_PATTERN.matcher(uri);\n        System.out.println(\"--------------->\" + \"/\" + uri);\n        while (matcher.matches()) {\n\n            System.out.println(matcher.group());\n        }\n        // for (int index = 0; index < matcher.groupCount(); index++) {\n        // System.out.println(matcher.group());\n        // }\n    }\n\n    @Test\n    public void doSomeBasicMethodTest() throws Exception {\n        CloseableHttpClient httpclient = HttpClients.createDefault();\n\n        HttpGet httpget = new HttpGet(\"http://localhost:9090/user/blabla\");\n        CloseableHttpResponse response = httpclient.execute(httpget);\n        HttpEntity entity = response.getEntity();\n        String string = new String(readContents(entity), \"UTF-8\");\n        Assert.assertEquals(\n                \"<html><body>User handler. Method: GET<br><h1>Uri parameters:</h1><div> Param: id&nbsp;Value: blabla</div><h1>Query parameters:</h1></body></html>\", string);\n        response.close();\n\n        HttpPost httppost = new HttpPost(\"http://localhost:9090/user/blabla\");\n        response = httpclient.execute(httppost);\n        entity = response.getEntity();\n        string = new String(readContents(entity), \"UTF-8\");\n        Assert.assertEquals(\n                \"<html><body>User handler. Method: POST<br><h1>Uri parameters:</h1><div> Param: id&nbsp;Value: blabla</div><h1>Query parameters:</h1></body></html>\", string);\n        response.close();\n\n        HttpPut httpgput = new HttpPut(\"http://localhost:9090/user/blabla\");\n        response = httpclient.execute(httpgput);\n        entity = response.getEntity();\n        string = new String(readContents(entity), \"UTF-8\");\n        Assert.assertEquals(\n                \"<html><body>User handler. Method: PUT<br><h1>Uri parameters:</h1><div> Param: id&nbsp;Value: blabla</div><h1>Query parameters:</h1></body></html>\", string);\n        response.close();\n\n        HttpDelete httpdelete = new HttpDelete(\"http://localhost:9090/user/blabla\");\n        response = httpclient.execute(httpdelete);\n        entity = response.getEntity();\n        string = new String(readContents(entity), \"UTF-8\");\n        Assert.assertEquals(\n                \"<html><body>User handler. Method: DELETE<br><h1>Uri parameters:</h1><div> Param: id&nbsp;Value: blabla</div><h1>Query parameters:</h1></body></html>\", string);\n        response.close();\n    }\n\n    @Test\n    public void doEncodedRequest() throws ClientProtocolException, IOException {\n        CloseableHttpClient httpclient = HttpClients.createDefault();\n        HttpGet httpget = new HttpGet(\"http://localhost:9090/general/param%201/param%202\");\n        CloseableHttpResponse response = httpclient.execute(httpget);\n        Assert.assertEquals(Status.OK.getRequestStatus(), response.getStatusLine().getStatusCode());\n    }\n\n    @Test\n    public void doNonRouterRequest() throws Exception {\n        CloseableHttpClient httpclient = HttpClients.createDefault();\n\n        HttpGet httpget = new HttpGet(\"http://localhost:9090/test\");\n        CloseableHttpResponse response = httpclient.execute(httpget);\n        HttpEntity entity = response.getEntity();\n        String string = new String(readContents(entity), \"UTF-8\");\n        Assert.assertEquals(\"Return: java.lang.String.toString() -> \", string);\n        response.close();\n    }\n\n    @Test\n    public void doExceptionRequest() throws Exception {\n        CloseableHttpClient httpclient = HttpClients.createDefault();\n\n        HttpGet httpget = new HttpGet(\"http://localhost:9090/interface\");\n        CloseableHttpResponse response = httpclient.execute(httpget);\n        HttpEntity entity = response.getEntity();\n        String string = new String(readContents(entity), \"UTF-8\");\n        Assert.assertEquals(\"Error: java.lang.InstantiationException : org.nanohttpd.router.RouterNanoHTTPD$UriResponder\", string);\n        response.close();\n    }\n\n    @Test\n    public void doDeletedRoute() throws Exception {\n        CloseableHttpClient httpclient = HttpClients.createDefault();\n\n        HttpGet httpget = new HttpGet(\"http://localhost:9090/toBeDeleted\");\n        CloseableHttpResponse response = httpclient.execute(httpget);\n        HttpEntity entity = response.getEntity();\n        String string = new String(readContents(entity), \"UTF-8\");\n        Assert.assertEquals(\"<html><body><h3>Error 404: the requested page doesn't exist.</h3></body></html>\", string);\n        response.close();\n    }\n\n    @Test\n    public void doUriSelection1() throws Exception {\n        CloseableHttpClient httpclient = HttpClients.createDefault();\n\n        HttpGet httpget = new HttpGet(\"http://localhost:9090/user/help\");\n        CloseableHttpResponse response = httpclient.execute(httpget);\n        HttpEntity entity = response.getEntity();\n        String string = new String(readContents(entity), \"UTF-8\");\n        Assert.assertEquals(\"<html><body><h1>Url: /user/help</h1><br><p>no params in url</p><br>\", string);\n        response.close();\n    }\n\n    @Test\n    public void doStreamOfData() throws Exception {\n        CloseableHttpClient httpclient = HttpClients.createDefault();\n\n        HttpGet httpget = new HttpGet(\"http://localhost:9090/stream\");\n        CloseableHttpResponse response = httpclient.execute(httpget);\n        HttpEntity entity = response.getEntity();\n        String string = new String(readContents(entity), \"UTF-8\");\n        Assert.assertEquals(\"a stream of data ;-)\", string);\n        response.close();\n    }\n\n    @Test(expected = IllegalStateException.class)\n    public void illegalMethod1() throws Exception {\n        new AppNanolets.UserHandler().getData();\n    }\n\n    @Test(expected = IllegalStateException.class)\n    public void illegalMethod2() throws Exception {\n        new RouterNanoHTTPD.GeneralHandler().getText();\n    }\n\n    @Test(expected = IllegalStateException.class)\n    public void illegalMethod3() throws Exception {\n        new RouterNanoHTTPD.StaticPageHandler().getText();\n    }\n\n    @Test(expected = IllegalStateException.class)\n    public void illegalMethod4() throws Exception {\n        new RouterNanoHTTPD.StaticPageHandler().getMimeType();\n    }\n\n    @Test(expected = ClassCastException.class)\n    public void checkIniParameter1() throws Exception {\n        new RouterNanoHTTPD.UriResource(\"browse\", 100, null, \"init\").initParameter(String.class);\n        new RouterNanoHTTPD.UriResource(\"browse\", 100, null, \"init\").initParameter(Integer.class);\n    }\n\n    @Test\n    public void checkIniParameter2() throws Exception {\n        Assert.assertEquals(\"init\", new RouterNanoHTTPD.UriResource(\"browse\", 100, null, \"init\").initParameter(String.class));\n        Assert.assertNull(new RouterNanoHTTPD.UriResource(\"browse\", 100, null).initParameter(String.class));\n    }\n\n    @Test\n    public void doGeneralParams() throws Exception {\n        CloseableHttpClient httpclient = HttpClients.createDefault();\n\n        HttpGet httpget = new HttpGet(\"http://localhost:9090/general/value1/value2?param3=value3&param4=value4\");\n\n        CloseableHttpResponse response = httpclient.execute(httpget);\n        HttpEntity entity = response.getEntity();\n        String string = new String(readContents(entity), \"UTF-8\");\n        Assert.assertEquals(\"<html><body><h1>Url: /general/value1/value2</h1><br><p>Param 'param3' = value3</p><p>Param 'param4' = value4</p>\", string);\n        response.close();\n    }\n\n    @Test\n    public void doIndexHandler() throws Exception {\n        CloseableHttpClient httpclient = HttpClients.createDefault();\n\n        HttpGet httpget = new HttpGet(\"http://localhost:9090/index.html\");\n        CloseableHttpResponse response = httpclient.execute(httpget);\n        HttpEntity entity = response.getEntity();\n        String string = new String(readContents(entity), \"UTF-8\");\n        Assert.assertEquals(\"<html><body><h2>Hello world!</h3></body></html>\", string);\n        response.close();\n    }\n\n    @Test\n    public void doMissingHandler() throws Exception {\n        CloseableHttpClient httpclient = HttpClients.createDefault();\n\n        HttpGet httpget = new HttpGet(\"http://localhost:9090/photos/abc/def\");\n        CloseableHttpResponse response = httpclient.execute(httpget);\n        HttpEntity entity = response.getEntity();\n        String string = new String(readContents(entity), \"UTF-8\");\n        Assert.assertEquals(\"<html><body><h2>The uri is mapped in the router, but no handler is specified. <br> Status: Not implemented!</h3></body></html>\", string);\n        response.close();\n    }\n\n    @Test\n    public void uriToString() throws Exception {\n        Assert.assertEquals(//\n                \"UrlResource{uri='photos/:customer_id/:photo_id', urlParts=[customer_id, photo_id]}\",//\n                new UriResource(\"/photos/:customer_id/:photo_id\", 100, GeneralHandler.class).toString());\n    }\n\n    @Test\n    public void doOtherMethod() throws Exception {\n        CloseableHttpClient httpclient = HttpClients.createDefault();\n\n        HttpTrace httphead = new HttpTrace(\"http://localhost:9090/index.html\");\n        CloseableHttpResponse response = httpclient.execute(httphead);\n        HttpEntity entity = response.getEntity();\n        String string = new String(readContents(entity), \"UTF-8\");\n        Assert.assertEquals(\"<html><body><h2>Hello world!</h3></body></html>\", string);\n        response.close();\n    }\n\n    @Test\n    public void normalize() throws Exception {\n        Assert.assertNull(RouterNanoHTTPD.normalizeUri(null));\n        Assert.assertEquals(\"\", RouterNanoHTTPD.normalizeUri(\"/\"));\n        Assert.assertEquals(\"xxx/yyy\", RouterNanoHTTPD.normalizeUri(\"/xxx/yyy\"));\n        Assert.assertEquals(\"xxx/yyy\", RouterNanoHTTPD.normalizeUri(\"/xxx/yyy/\"));\n    }\n\n    private byte[] readContents(HttpEntity entity) throws IOException {\n        InputStream instream = entity.getContent();\n        return readContents(instream);\n    }\n\n    private byte[] readContents(InputStream instream) throws IOException {\n        byte[] bytes;\n        ByteArrayOutputStream out = new ByteArrayOutputStream();\n\n        try {\n            byte[] buffer = new byte[1024];\n            int count;\n            while ((count = instream.read(buffer)) >= 0) {\n                out.write(buffer, 0, count);\n            }\n            bytes = out.toByteArray();\n        } finally {\n            instream.close();\n        }\n        return bytes;\n    }\n\n    @Test\n    public void staticFiles() throws Exception {\n        CloseableHttpClient httpclient = HttpClients.createDefault();\n\n        HttpTrace httphead = new HttpTrace(\"http://localhost:9090/browse/blabla.html\");\n        CloseableHttpResponse response = httpclient.execute(httphead);\n        HttpEntity entity = response.getEntity();\n        String string = new String(readContents(entity), \"UTF-8\");\n        Assert.assertEquals(\"<html><body><h3>just a page</h3></body></html>\", string);\n        response.close();\n\n        httphead = new HttpTrace(\"http://localhost:9090/browse/dir/blabla.html\");\n        response = httpclient.execute(httphead);\n        entity = response.getEntity();\n        string = new String(readContents(entity), \"UTF-8\");\n        Assert.assertEquals(\"<html><body><h3>just an other page</h3></body></html>\", string);\n        response.close();\n\n        httphead = new HttpTrace(\"http://localhost:9090/browse/dir/nanohttpd_logo.png\");\n        response = httpclient.execute(httphead);\n        entity = response.getEntity();\n        Assert.assertEquals(\"image/png\", entity.getContentType().getValue());\n        response.close();\n\n        httphead = new HttpTrace(\"http://localhost:9090/browse/dir/xxx.html\");\n        response = httpclient.execute(httphead);\n        entity = response.getEntity();\n        string = new String(readContents(entity), \"UTF-8\");\n        Assert.assertEquals(\"<html><body><h3>Error 404: the requested page doesn't exist.</h3></body></html>\", string);\n        response.close();\n\n        httphead = new HttpTrace(\"http://localhost:9090/browse/dir/\");\n        response = httpclient.execute(httphead);\n        entity = response.getEntity();\n        string = new String(readContents(entity), \"UTF-8\");\n        Assert.assertEquals(\"<html><body><h3>just an index page</h3></body></html>\", string);\n        response.close();\n\n        httphead = new HttpTrace(\"http://localhost:9090/browse/exception.html\");\n        response = httpclient.execute(httphead);\n        Assert.assertEquals(Status.REQUEST_TIMEOUT.getRequestStatus(), response.getStatusLine().getStatusCode());\n        entity = response.getEntity();\n        string = new String(readContents(entity), \"UTF-8\");\n        Assert.assertEquals(\"\", string);\n        response.close();\n    }\n\n    @AfterClass\n    public static void tearDown() throws Exception {\n        stdIn.write(\"\\n\\n\".getBytes());\n        serverStartThread.join(2000);\n        Assert.assertFalse(serverStartThread.isAlive());\n    }\n\n    @Test\n    public void testGeneralHandlerGetStatus() {\n        Assert.assertEquals(\"GeneralHandler#getStatus should return OK status\", Status.OK, new RouterNanoHTTPD.GeneralHandler().getStatus());\n    }\n\n    @Test\n    public void testStaticPageHandlerGetStatus() {\n        Assert.assertEquals(\"StaticPageHandler#getStatus should return OK status\", Status.OK, new RouterNanoHTTPD.StaticPageHandler().getStatus());\n    }\n\n    @Test\n    public void testError404UriHandlerGetStatus() {\n        Assert.assertEquals(\"Error404UriHandler#getStatus should return NOT_FOUND status\", Status.NOT_FOUND, new RouterNanoHTTPD.Error404UriHandler().getStatus());\n    }\n\n    @Test\n    public void testError404UriHandlerGetMimeType() {\n        Assert.assertEquals(\"Error404UriHandler mime type should be text/html\", \"text/html\", new RouterNanoHTTPD.Error404UriHandler().getMimeType());\n    }\n\n    @Test\n    public void testNotImplementedHandlerGetStatus() {\n        Assert.assertEquals(\"NotImplementedHandler#getStatus should return OK status\", Status.OK, new RouterNanoHTTPD.NotImplementedHandler().getStatus());\n    }\n\n    @Test\n    public void testIndexHandlerGetStatus() {\n        Assert.assertEquals(\"IndexHandler#getStatus should return OK status\", Status.OK, new RouterNanoHTTPD.IndexHandler().getStatus());\n    }\n\n    @Test\n    public void testIndexHandlerGetMimeType() {\n        Assert.assertEquals(\"IndexHandler mime type should be text/html\", \"text/html\", new RouterNanoHTTPD.IndexHandler().getMimeType());\n    }\n\n    @Test\n    public void testNotImplementedHandlerGetMimeType() {\n        Assert.assertEquals(\"NotImplementedHandler mime type should be text/html\", \"text/html\", new RouterNanoHTTPD.NotImplementedHandler().getMimeType());\n    }\n\n    @Test\n    public void testBaseRoutePrioritizerAddNullRoute() {\n        DefaultRoutePrioritizer routePrioritizer = new DefaultRoutePrioritizer();\n        routePrioritizer.addRoute(null, 100, null);\n        Assert.assertEquals(0, routePrioritizer.getPrioritizedRoutes().size());\n    }\n\n    @Test\n    public void testInsertionOrderRoutePrioritizer() throws IOException {\n        InsertionOrderRoutePrioritizer routePrioritizer = new InsertionOrderRoutePrioritizer();\n\n        Class<?> handler1 = String.class;\n        Class<?> handler2 = Boolean.class;\n        Class<?> handler3 = Long.class;\n\n        ArrayList<Class<?>> classes = new ArrayList<Class<?>>();\n        classes.add(handler1);\n        classes.add(handler2);\n        classes.add(handler3);\n\n        routePrioritizer.addRoute(\"/user\", 100, handler1);\n        routePrioritizer.addRoute(\"/user\", 100, handler2);\n        routePrioritizer.addRoute(\"/user\", 100, handler3);\n        List<UriResource> prioritizedResources = new ArrayList<UriResource>();\n        prioritizedResources.addAll(routePrioritizer.getPrioritizedRoutes());\n\n        for (int i = 0; i < classes.size(); i++) {\n            Class<?> handler = classes.get(i);\n            UriResource resource = prioritizedResources.get(i);\n\n            InputStream inputStream = resource.process(null, null).getData();\n            byte[] bytes = new byte[inputStream.available()];\n            inputStream.read(bytes);\n            String message = new String(bytes);\n\n            Assert.assertTrue(message.contains(handler.getCanonicalName()));\n\n        }\n    }\n\n    @Test\n    public void testProvidedPriorityRoutePrioritizerNullUri() {\n        ProvidedPriorityRoutePrioritizer routePrioritizer = new ProvidedPriorityRoutePrioritizer();\n        Assert.assertEquals(0, routePrioritizer.getPrioritizedRoutes().size());\n        routePrioritizer.addRoute(null, 100, null);\n        Assert.assertEquals(0, routePrioritizer.getPrioritizedRoutes().size());\n    }\n\n    @Test\n    public void testProvidedPriorityRoutePrioritizerNullHandler() {\n        ProvidedPriorityRoutePrioritizer routePrioritizer = new ProvidedPriorityRoutePrioritizer();\n        Assert.assertEquals(0, routePrioritizer.getPrioritizedRoutes().size());\n        routePrioritizer.addRoute(\"/help\", 100, null);\n        Assert.assertEquals(1, routePrioritizer.getPrioritizedRoutes().size());\n    }\n\n    @Test\n    public void testProvidedPriorityRoutePrioritizer() throws IOException {\n        ProvidedPriorityRoutePrioritizer routePrioritizer = new ProvidedPriorityRoutePrioritizer();\n\n        Class<?> handler1 = String.class;\n        Class<?> handler2 = Boolean.class;\n        Class<?> handler3 = Long.class;\n\n        ArrayList<Class<?>> classes = new ArrayList<Class<?>>();\n        classes.add(handler2);\n        classes.add(handler1);\n        classes.add(handler3);\n\n        routePrioritizer.addRoute(\"/user\", 101, handler1);\n        routePrioritizer.addRoute(\"/user\", 100, handler2);\n        routePrioritizer.addRoute(\"/user\", 102, handler3);\n        List<UriResource> prioritizedResources = new ArrayList<UriResource>();\n        prioritizedResources.addAll(routePrioritizer.getPrioritizedRoutes());\n\n        for (int i = 0; i < classes.size(); i++) {\n            Class<?> handler = classes.get(i);\n            UriResource resource = prioritizedResources.get(i);\n\n            InputStream inputStream = resource.process(null, null).getData();\n            byte[] bytes = new byte[inputStream.available()];\n            inputStream.read(bytes);\n            String message = new String(bytes);\n\n            Assert.assertTrue(message.contains(handler.getCanonicalName()));\n        }\n    }\n\n    @Test\n    public void testUriResourceComparator() {\n        UriResource r1 = new UriResource(\"uri\", null);\n        r1.setPriority(100);\n        Assert.assertTrue(r1.compareTo(null) >= 1);\n\n        UriResource r2 = new UriResource(\"uri\", null);\n        r2.setPriority(100);\n        Assert.assertEquals(0, r1.compareTo(r2));\n\n        r2.setPriority(99);\n        Assert.assertTrue(r1.compareTo(r2) >= 1);\n\n        r2.setPriority(101);\n        Assert.assertTrue(r1.compareTo(r2) <= 1);\n    }\n\n    @Test\n    public void testUriResourceMatch() {\n        UriResource resource = new RouterNanoHTTPD.UriResource(\"browse\", 100, null, \"init\");\n        Assert.assertNull(\"UriResource should not match incorrect URL, and thus, should not return a URI parameter map\", resource.match(\"/xyz/pqr/\"));\n        Assert.assertNotNull(\"UriResource should match the correct URL, and thus, should return a URI parameter map\", resource.match(\"browse\"));\n    }\n\n    @Test\n    public void testRoutePrioritizerRemoveRouteNoRouteMatches() {\n        DefaultRoutePrioritizer prioritizer = new DefaultRoutePrioritizer();\n        prioritizer.addRoute(\"/world\", 100, NotImplementedHandler.class);\n        prioritizer.removeRoute(\"/hello\");\n\n        Assert.assertEquals(1, prioritizer.getPrioritizedRoutes().size());\n    }\n\n    @Test\n    public void testHandlerSetters() throws Exception {\n        final UriResponder notFoundHandler = new GeneralHandler() {\n        };\n        final UriResponder notImplementedHandler = new GeneralHandler() {\n        };\n\n        TestRouter router = new TestRouter();\n\n        RouterNanoHTTPD routerNanoHttpd = new RouterNanoHTTPD(9999);\n\n        Field routerField = RouterNanoHTTPD.class.getDeclaredField(\"router\");\n        routerField.setAccessible(true);\n        routerField.set(routerNanoHttpd, router);\n\n        routerNanoHttpd.setNotFoundHandler(notFoundHandler.getClass());\n        routerNanoHttpd.setNotImplementedHandler(notImplementedHandler.getClass());\n\n        Assert.assertEquals(notFoundHandler.getClass(), router.notFoundHandlerClass);\n        Assert.assertEquals(notImplementedHandler.getClass(), router.notImplementedHandlerClass);\n    }\n\n    private static final class TestRouter extends UriRouter {\n\n        private Class<?> notFoundHandlerClass;\n\n        private Class<?> notImplementedHandlerClass;\n\n        @Override\n        public void setNotFoundHandler(Class<?> handler) {\n            notFoundHandlerClass = handler;\n        }\n\n        @Override\n        public void setNotImplemented(Class<?> handler) {\n            notImplementedHandlerClass = handler;\n        }\n    }\n}\n"
  },
  {
    "path": "nanolets/src/test/resources/blabla.html",
    "content": "<html><body><h3>just a page</h3></body></html>"
  },
  {
    "path": "nanolets/src/test/resources/dir/blabla.html",
    "content": "<html><body><h3>just an other page</h3></body></html>"
  },
  {
    "path": "nanolets/src/test/resources/dir/index.htm",
    "content": "<html><body><h3>just an index page</h3></body></html>"
  },
  {
    "path": "nanolets/src/test/resources/exception.html",
    "content": "this will throw an io exception"
  },
  {
    "path": "pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<parent>\n\t\t<groupId>org.sonatype.oss</groupId>\n\t\t<artifactId>oss-parent</artifactId>\n\t\t<version>7</version>\n\t</parent>\n\t<groupId>org.nanohttpd</groupId>\n\t<artifactId>nanohttpd-project</artifactId>\n\t<version>2.3.2-SNAPSHOT</version>\n\t<packaging>pom</packaging>\n\t<name>NanoHttpd-Project</name>\n\t<description>NanoHttpd is a light-weight HTTP server designed for embedding in other applications.</description>\n\t<url>http://www.nanohttpd.org</url>\n\t<scm>\n\t\t<connection>scm:git:https://github.com/NanoHttpd/nanohttpd.git</connection>\n\t\t<developerConnection>scm:git:https://github.com/NanoHttpd/nanohttpd.git</developerConnection>\n\t\t<url>https://github.com/NanoHttpd/nanohttpd</url>\n\t\t<tag>HEAD</tag>\n\t</scm>\n\t<organization>\n\t\t<name>nanohttpd</name>\n\t</organization>\n\t<distributionManagement>\n\t\t<repository>\n\t\t\t<id>sonatype-nexus-staging</id>\n\t\t\t<name>nanohttpd sonytype Maven 2 repository</name>\n\t\t\t<url>https://oss.sonatype.org/service/local/staging/deploy/maven2</url>\n\t\t</repository>\n\t\t<snapshotRepository>\n\t\t\t<id>sonatype-nexus-staging</id>\n\t\t\t<name>nanohttpd sonytype Snapshot Maven 2 repository</name>\n\t\t\t<url>https://oss.sonatype.org/content/repositories/snapshots</url>\n\t\t</snapshotRepository>\n\t\t<site>\n\t\t\t<id>private-deploy</id>\n\t\t\t<name>private Project Site</name>\n\t\t\t<url>scp://nanohttpd.org:33333/home/nanohttpd/public_html</url>\n\t\t</site>\n\t</distributionManagement>\n\t<inceptionYear>2012</inceptionYear>\n\t<developers>\n\t\t<developer>\n\t\t\t<id>psh</id>\n\t\t\t<name>Paul Hawke</name>\n\t\t\t<url>http://www.linkedin.com/in/paulhawke</url>\n\t\t\t<roles>\n\t\t\t\t<role>Administrator</role>\n\t\t\t\t<role>Developer</role>\n\t\t\t</roles>\n\t\t\t<properties>\n\t\t\t\t<picUrl>https://avatars2.githubusercontent.com/u/407647</picUrl>\n\t\t\t</properties>\n\t\t</developer>\n\t\t<developer>\n\t\t\t<id>elonen</id>\n\t\t\t<name>Jarno Elonen</name>\n\t\t\t<email>elonen [at] iki [dot] fi</email>\n\t\t\t<roles>\n\t\t\t\t<role>Administrator</role>\n\t\t\t\t<role>Developer</role>\n\t\t\t</roles>\n\t\t\t<properties>\n\t\t\t\t<picUrl>https://avatars0.githubusercontent.com/u/2125766</picUrl>\n\t\t\t</properties>\n\t\t</developer>\n\t\t<developer>\n\t\t\t<id>ritchieGitHub</id>\n\t\t\t<name>Richard van Nieuwenhoven</name>\n\t\t\t<email>ritchie [at] gmx [dot] at</email>\n\t\t\t<roles>\n\t\t\t\t<role>Administrator</role>\n\t\t\t\t<role>Developer</role>\n\t\t\t</roles>\n\t\t\t<properties>\n\t\t\t\t<picUrl>http://www.gravatar.com/avatar/9e2c2e7aa94335b72952a4b2d56bfc89.png</picUrl>\n\t\t\t</properties>\n\t\t</developer>\n\t\t<developer>\n\t\t\t<id>LordFokas</id>\n\t\t\t<name>Diogo Duarte</name>\n\t\t\t<email>diogo.duarte [at] techie [dot] com</email>\n\t\t\t<roles>\n\t\t\t\t<role>Administrator</role>\n\t\t\t\t<role>Developer</role>\n\t\t\t</roles>\n\t\t\t<properties>\n\t\t\t\t<picUrl>https://avatars1.githubusercontent.com/u/3021352</picUrl>\n\t\t\t</properties>\n\t\t</developer>\n\t</developers>\n\t<issueManagement>\n\t\t<system>github</system>\n\t\t<url>https://github.com/NanoHttpd/nanohttpd/issues</url>\n\t</issueManagement>\n\t<modules>\n\t\t<module>core</module>\n\t\t<module>samples</module>\n\t\t<module>webserver</module>\n\t\t<module>websocket</module>\n\t\t<module>markdown-plugin</module>\n\t\t<module>nanolets</module>\n\t\t<module>fileupload</module>\n\t</modules>\n\t<licenses>\n\t\t<license>\n\t\t\t<name>The BSD 3-Clause License</name>\n\t\t\t<url>http://opensource.org/licenses/BSD-3-Clause</url>\n\t\t\t<distribution>repo</distribution>\n\t\t</license>\n\t</licenses>\n\t<build>\n\t\t<extensions>\n\t\t\t<extension>\n\t\t\t\t<groupId>org.apache.maven.wagon</groupId>\n\t\t\t\t<artifactId>wagon-ssh</artifactId>\n\t\t\t\t<version>2.7</version>\n\t\t\t</extension>\n\t\t</extensions>\n\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-compiler-plugin</artifactId>\n\t\t\t\t<version>3.3</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<source>1.7</source>\n\t\t\t\t\t<target>1.7</target>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-javadoc-plugin</artifactId>\n\t\t\t\t<version>2.10.1</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<aggregate>false</aggregate>\n\t\t\t\t\t<failOnError>false</failOnError>\n\t\t\t\t</configuration>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>attach-javadocs</id>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>jar</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-release-plugin</artifactId>\n\t\t\t\t<version>2.5.1</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<mavenExecutorId>forked-path</mavenExecutorId>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.tinyjee.dim</groupId>\n\t\t\t\t<artifactId>doxia-include-macro</artifactId>\n\t\t\t\t<version>1.1</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>initialize-doxia-include-macro</id>\n\t\t\t\t\t\t<phase>pre-site</phase>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>initialize</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-site-plugin</artifactId>\n\t\t\t\t<version>3.4</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<chmod>false</chmod>\n\t\t\t\t</configuration>\n\t\t\t\t<dependencies>\n\t\t\t\t\t<dependency>\n\t\t\t\t\t\t<groupId>org.apache.maven.wagon</groupId>\n\t\t\t\t\t\t<artifactId>wagon-ssh</artifactId>\n\t\t\t\t\t\t<version>2.7</version>\n\t\t\t\t\t</dependency>\n\t\t\t\t\t<dependency>\n\t\t\t\t\t\t<groupId>org.tinyjee.dim</groupId>\n\t\t\t\t\t\t<artifactId>doxia-include-macro</artifactId>\n\t\t\t\t\t\t<version>1.1</version>\n\t\t\t\t\t</dependency>\n\t\t\t\t\t<dependency>\n\t\t\t\t\t\t<groupId>net.ju-n.maven.doxia</groupId>\n\t\t\t\t\t\t<artifactId>doxia-module-markdown</artifactId>\n\t\t\t\t\t\t<version>1.0.0</version>\n\t\t\t\t\t</dependency>\n\t\t\t\t</dependencies>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.codehaus.mojo</groupId>\n\t\t\t\t<artifactId>license-maven-plugin</artifactId>\n\t\t\t\t<version>1.7</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<verbose>false</verbose>\n\t\t\t\t</configuration>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>first</id>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>update-file-header</goal>\n\t\t\t\t\t\t\t<goal>update-project-license</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<phase>process-sources</phase>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<licenseName>bsd_3</licenseName>\n\t\t\t\t\t\t\t<roots>\n\t\t\t\t\t\t\t\t<root>src/main/java</root>\n\t\t\t\t\t\t\t\t<root>src/test/java</root>\n\t\t\t\t\t\t\t</roots>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-surefire-plugin</artifactId>\n\t\t\t\t<version>2.18.1</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<forkCount>1</forkCount>\n\t\t\t\t\t<reuseForks>false</reuseForks>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.jacoco</groupId>\n\t\t\t\t<artifactId>jacoco-maven-plugin</artifactId>\n\t\t\t\t<version>0.7.4.201502262128</version>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>default-prepare-agent</id>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>prepare-agent</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>default-report</id>\n\t\t\t\t\t\t<phase>prepare-package</phase>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>report</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>default-check</id>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>check</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<rules>\n\t\t\t\t\t\t\t\t<rule>\n\t\t\t\t\t\t\t\t\t<element>BUNDLE</element>\n\t\t\t\t\t\t\t\t\t<limits>\n\t\t\t\t\t\t\t\t\t\t<limit>\n\t\t\t\t\t\t\t\t\t\t\t<counter>LINE</counter>\n\t\t\t\t\t\t\t\t\t\t\t<value>COVEREDRATIO</value>\n\t\t\t\t\t\t\t\t\t\t\t<minimum>${minimal.coverage}</minimum>\n\t\t\t\t\t\t\t\t\t\t</limit>\n\t\t\t\t\t\t\t\t\t</limits>\n\t\t\t\t\t\t\t\t</rule>\n\t\t\t\t\t\t\t</rules>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<reporting>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-project-info-reports-plugin</artifactId>\n\t\t\t\t<version>2.8</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<dependencyDetailsEnabled>false</dependencyDetailsEnabled>\n\t\t\t\t\t<dependencyLocationsEnabled>false</dependencyLocationsEnabled>\n\t\t\t\t</configuration>\n\t\t\t\t<reportSets>\n\t\t\t\t\t<reportSet>\n\t\t\t\t\t\t<reports>\n\t\t\t\t\t\t\t<report>index</report>\n\t\t\t\t\t\t\t<report>dependencies</report>\n\t\t\t\t\t\t\t<report>project-team</report>\n\t\t\t\t\t\t\t<report>mailing-list</report>\n\t\t\t\t\t\t\t<report>cim</report>\n\t\t\t\t\t\t\t<report>issue-tracking</report>\n\t\t\t\t\t\t\t<report>license</report>\n\t\t\t\t\t\t\t<report>scm</report>\n\t\t\t\t\t\t</reports>\n\t\t\t\t\t</reportSet>\n\t\t\t\t</reportSets>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-javadoc-plugin</artifactId>\n\t\t\t\t<version>2.10.1</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<failOnError>false</failOnError>\n\t\t\t\t\t<aggregate>false</aggregate>\n\t\t\t\t</configuration>\n\t\t\t\t<reportSets>\n\t\t\t\t\t<reportSet><!-- by default, id = \"default\" -->\n\t\t\t\t\t\t<reports><!-- select non-aggregate reports -->\n\t\t\t\t\t\t\t<report>javadoc-no-fork</report>\n\t\t\t\t\t\t</reports>\n\t\t\t\t\t</reportSet>\n\t\t\t\t</reportSets>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-jxr-plugin</artifactId>\n\t\t\t\t<version>2.4</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<linkJavadoc>true</linkJavadoc>\n\t\t\t\t\t<skip>${nanohttpd.nonjavamodule}</skip>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-pmd-plugin</artifactId>\n\t\t\t\t<version>3.2</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<linkXref>true</linkXref>\n\t\t\t\t\t<sourceEncoding>UTF-8</sourceEncoding>\n\t\t\t\t\t<targetJdk>1.7</targetJdk>\n\t\t\t\t\t<skipEmptyReport>false</skipEmptyReport>\n\t\t\t\t\t<minimumTokens>50</minimumTokens>\n\t\t\t\t</configuration>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.codehaus.mojo</groupId>\n\t\t\t\t<artifactId>taglist-maven-plugin</artifactId>\n\t\t\t\t<version>2.4</version>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.codehaus.mojo</groupId>\n\t\t\t\t<artifactId>findbugs-maven-plugin</artifactId>\n\t\t\t\t<version>3.0.0</version>\n\t\t\t</plugin>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.jacoco</groupId>\n\t\t\t\t<artifactId>jacoco-maven-plugin</artifactId>\n\t\t\t\t<version>0.7.4.201502262128</version>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</reporting>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>junit</groupId>\n\t\t\t<artifactId>junit</artifactId>\n\t\t\t<version>4.12</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t</dependencies>\n\t<profiles>\n\t\t<profile>\n\t\t\t<id>release-sign-artifacts</id>\n\t\t\t<activation>\n\t\t\t\t<property>\n\t\t\t\t\t<name>performRelease</name>\n\t\t\t\t\t<value>true</value>\n\t\t\t\t</property>\n\t\t\t</activation>\n\t\t\t<build>\n\t\t\t\t<plugins>\n\t\t\t\t\t<plugin>\n\t\t\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t\t\t<artifactId>maven-gpg-plugin</artifactId>\n\t\t\t\t\t\t<executions>\n\t\t\t\t\t\t\t<execution>\n\t\t\t\t\t\t\t\t<id>sign-artifacts</id>\n\t\t\t\t\t\t\t\t<phase>verify</phase>\n\t\t\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t\t\t<goal>sign</goal>\n\t\t\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t\t\t<!-- if the local user is not the key user use -Dgpg.keyname=XXXX -->\n\t\t\t\t\t\t\t</execution>\n\t\t\t\t\t\t</executions>\n\t\t\t\t\t</plugin>\n\t\t\t\t</plugins>\n\t\t\t</build>\n\t\t</profile>\n\t\t<profile>\n\t\t\t<id>java</id>\n\t\t\t<activation>\n\t\t\t\t<file>\n\t\t\t\t\t<exists>src/main/java</exists>\n\t\t\t\t</file>\n\t\t\t</activation>\n\t\t\t<build>\n\t\t\t\t<plugins>\n\t\t\t\t\t<plugin>\n\t\t\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t\t\t<artifactId>maven-checkstyle-plugin</artifactId>\n\t\t\t\t\t\t<version>2.15</version>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<configLocation>${project.basedir}/../src/main/checkstyle/nanohttpd-style.xml</configLocation>\n\t\t\t\t\t\t\t<suppressionsLocation>${project.basedir}/../src/main/checkstyle/checkstyle-suppressions.xml</suppressionsLocation>\n\t\t\t\t\t\t\t<encoding>UTF-8</encoding>\n\t\t\t\t\t\t\t<consoleOutput>true</consoleOutput>\n\t\t\t\t\t\t\t<failsOnError>false</failsOnError>\n\t\t\t\t\t\t\t<linkXRef>true</linkXRef>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</plugin>\n\t\t\t\t\t<plugin>\n\t\t\t\t\t\t<groupId>com.googlecode.maven-java-formatter-plugin</groupId>\n\t\t\t\t\t\t<artifactId>maven-java-formatter-plugin</artifactId>\n\t\t\t\t\t\t<version>0.4</version>\n\t\t\t\t\t\t<executions>\n\t\t\t\t\t\t\t<execution>\n\t\t\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t\t\t<goal>format</goal>\n\t\t\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t\t</execution>\n\t\t\t\t\t\t</executions>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<configFile>${project.basedir}/../src/main/formatter/formatter.xml</configFile>\n\t\t\t\t\t\t\t<lineEnding>LF</lineEnding>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</plugin>\n\t\t\t\t</plugins>\n\t\t\t</build>\n\t\t\t<reporting>\n\t\t\t\t<plugins>\n\t\t\t\t\t<plugin>\n\t\t\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t\t\t<artifactId>maven-checkstyle-plugin</artifactId>\n\t\t\t\t\t\t<version>2.15</version>\n\t\t\t\t\t\t<reportSets>\n\t\t\t\t\t\t\t<reportSet>\n\t\t\t\t\t\t\t\t<reports>\n\t\t\t\t\t\t\t\t\t<report>checkstyle</report>\n\t\t\t\t\t\t\t\t</reports>\n\t\t\t\t\t\t\t</reportSet>\n\t\t\t\t\t\t</reportSets>\n\t\t\t\t\t</plugin>\n\t\t\t\t</plugins>\n\t\t\t</reporting>\n\t\t</profile>\n\t\t<profile>\n\t\t\t<id>parent-build</id>\n\t\t\t<activation>\n\t\t\t\t<file>\n\t\t\t\t\t<exists>core/pom.xml</exists>\n\t\t\t\t</file>\n\t\t\t</activation>\n\t\t\t<build>\n\t\t\t\t<plugins>\n\t\t\t\t\t<plugin>\n\t\t\t\t\t\t<groupId>org.jacoco</groupId>\n\t\t\t\t\t\t<artifactId>jacoco-maven-plugin</artifactId>\n\t\t\t\t\t\t<version>0.7.4.201502262128</version>\n\t\t\t\t\t\t<executions>\n\t\t\t\t\t\t\t<execution>\n\t\t\t\t\t\t\t\t<id>merge-report</id>\n\t\t\t\t\t\t\t\t<phase>package</phase>\n\t\t\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t\t\t<goal>merge</goal>\n\t\t\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t\t</execution>\n\t\t\t\t\t\t</executions>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<fileSets>\n\t\t\t\t\t\t\t\t<fileSet>\n\t\t\t\t\t\t\t\t\t<directory>${project.basedir}/..</directory>\n\t\t\t\t\t\t\t\t\t<includes>\n\t\t\t\t\t\t\t\t\t\t<include>*.exec</include>\n\t\t\t\t\t\t\t\t\t</includes>\n\t\t\t\t\t\t\t\t</fileSet>\n\t\t\t\t\t\t\t</fileSets>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</plugin>\n\t\t\t\t\t<plugin>\n\t\t\t\t\t\t<groupId>org.eluder.coveralls</groupId>\n\t\t\t\t\t\t<artifactId>coveralls-maven-plugin</artifactId>\n\t\t\t\t\t\t<version>3.1.0</version>\n\t\t\t\t\t</plugin>\n\t\t\t\t</plugins>\n\t\t\t</build>\n\t\t</profile>\n\t\t<profile>\n\t\t\t<id>use 1.7 compiler</id>\n\t\t\t<activation>\n\t\t\t\t<file>\n\t\t\t\t\t<exists>/usr/lib/jvm/java-7-openjdk-amd64/bin/javac</exists>\n\t\t\t\t</file>\n\t\t\t</activation>\n\t\t\t<build>\n\t\t\t\t<plugins>\n\t\t\t\t\t<plugin>\n\t\t\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t\t\t<artifactId>maven-compiler-plugin</artifactId>\n\t\t\t\t\t\t<version>3.3</version>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<source>1.7</source>\n\t\t\t\t\t\t\t<target>1.7</target>\n\t\t\t\t\t\t\t<verbose>true</verbose>\n\t\t\t\t\t\t\t<fork>true</fork>\n\t\t\t\t\t\t\t<executable>/usr/lib/jvm/java-7-openjdk-amd64/bin/javac</executable>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</plugin>\n\t\t\t\t</plugins>\n\t\t\t</build>\n\t\t</profile>\n\t</profiles>\n\t<properties>\n\t\t<minimal.coverage>0.77</minimal.coverage>\n\t</properties>\n</project>\n"
  },
  {
    "path": "relocation/nanohttpd/pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<parent>\n\t\t<groupId>com.nanohttpd</groupId>\n\t\t<artifactId>nanohttpd-project</artifactId>\n\t\t<version>2.2.0</version>\n\t</parent>\n\t<artifactId>nanohttpd</artifactId>\n\t<distributionManagement>\n\t\t<relocation>\n\t\t\t<groupId>org.nanohttpd</groupId>\n\t\t</relocation>\n\t</distributionManagement>\n</project>"
  },
  {
    "path": "relocation/nanohttpd/src/main/resources/relocated.txt",
    "content": "this project was relocated to the groupid org.nanohttpd starting with version 2.2.0"
  },
  {
    "path": "relocation/nanohttpd-samples/pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<parent>\n\t\t<groupId>com.nanohttpd</groupId>\n\t\t<artifactId>nanohttpd-project</artifactId>\n\t\t<version>2.2.0</version>\n\t</parent>\n\t<artifactId>nanohttpd-samples</artifactId>\n\t<distributionManagement>\n\t\t<relocation>\n\t\t\t<groupId>org.nanohttpd</groupId>\n\t\t</relocation>\n\t</distributionManagement>\n</project>"
  },
  {
    "path": "relocation/nanohttpd-samples/src/main/resources/relocated.txt",
    "content": "this project was relocated to the groupid org.nanohttpd starting with version 2.2.0"
  },
  {
    "path": "relocation/nanohttpd-webserver/pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<parent>\n\t\t<groupId>com.nanohttpd</groupId>\n\t\t<artifactId>nanohttpd-project</artifactId>\n\t\t<version>2.2.0</version>\n\t</parent>\n\t<artifactId>nanohttpd-webserver</artifactId>\n\t<distributionManagement>\n\t\t<relocation>\n\t\t\t<groupId>org.nanohttpd</groupId>\n\t\t</relocation>\n\t</distributionManagement>\n</project>"
  },
  {
    "path": "relocation/nanohttpd-webserver/src/main/resources/relocated.txt",
    "content": "this project was relocated to the groupid org.nanohttpd starting with version 2.2.0"
  },
  {
    "path": "relocation/nanohttpd-webserver-markdown-plugin/pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<parent>\n\t\t<groupId>com.nanohttpd</groupId>\n\t\t<artifactId>nanohttpd-project</artifactId>\n\t\t<version>2.2.0</version>\n\t</parent>\n\t<artifactId>nanohttpd-webserver-markdown-plugin</artifactId>\n\t<distributionManagement>\n\t\t<relocation>\n\t\t\t<groupId>org.nanohttpd</groupId>\n\t\t</relocation>\n\t</distributionManagement>\n</project>"
  },
  {
    "path": "relocation/nanohttpd-webserver-markdown-plugin/src/main/resources/relocated.txt",
    "content": "this project was relocated to the groupid org.nanohttpd starting with version 2.2.0"
  },
  {
    "path": "relocation/nanohttpd-websocket/pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<parent>\n\t\t<groupId>com.nanohttpd</groupId>\n\t\t<artifactId>nanohttpd-project</artifactId>\n\t\t<version>2.2.0</version>\n\t</parent>\n\t<artifactId>nanohttpd-websocket</artifactId>\n\t<distributionManagement>\n\t\t<relocation>\n\t\t\t<groupId>org.nanohttpd</groupId>\n\t\t</relocation>\n\t</distributionManagement>\n</project>"
  },
  {
    "path": "relocation/nanohttpd-websocket/src/main/resources/relocated.txt",
    "content": "this project was relocated to the groupid org.nanohttpd starting with version 2.2.0"
  },
  {
    "path": "relocation/pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n\txsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<parent>\n\t\t<groupId>org.sonatype.oss</groupId>\n\t\t<artifactId>oss-parent</artifactId>\n\t\t<version>7</version>\n\t</parent>\n\t<groupId>com.nanohttpd</groupId>\n\t<artifactId>nanohttpd-project</artifactId>\n\t<version>2.2.0</version>\n\t<packaging>pom</packaging>\n\t<distributionManagement>\n\t\t<repository>\n\t\t\t<id>sonatype-nexus-staging</id>\n\t\t\t<name>nanohttpd sonytype Maven 2 repository</name>\n\t\t\t<url>https://oss.sonatype.org/service/local/staging/deploy/maven2</url>\n\t\t</repository>\n\t\t<relocation>\n\t\t\t<groupId>org.nanohttpd</groupId>\n\t\t</relocation>\n\t</distributionManagement>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-gpg-plugin</artifactId>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>sign-artifacts</id>\n\t\t\t\t\t\t<phase>verify</phase>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>sign</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<!-- if the local user is not the key user use -Dgpg.keyname=XXXX -->\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<modules>\n\t\t<module>nanohttpd</module>\n\t\t<module>nanohttpd-webserver</module>\n\t\t<module>nanohttpd-webserver-markdown-plugin</module>\n\t\t<module>nanohttpd-samples</module>\n\t\t<module>nanohttpd-websocket</module>\n\t</modules>\n</project>"
  },
  {
    "path": "samples/.gitignore",
    "content": "/.settings/\n/LICENSE.txt\n"
  },
  {
    "path": "samples/build.gradle",
    "content": "description = 'NanoHttpd-Samples'\n\ndependencies {\n\tcompile project(':nanohttpd')\n\tcompile project(':nanohttpd-webserver')\n}\n\ntask wrapper(type: Wrapper) {\n\tgradleVersion = \"4.4.1\"\n}\n"
  },
  {
    "path": "samples/pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<parent>\n\t\t<groupId>org.nanohttpd</groupId>\n\t\t<artifactId>nanohttpd-project</artifactId>\n\t\t<version>2.3.2-SNAPSHOT</version>\n\t</parent>\n\t<artifactId>nanohttpd-samples</artifactId>\n\t<description>samples for nanohttpd</description>\n\t<packaging>jar</packaging>\n\t<name>NanoHttpd-Samples</name>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>${project.groupId}</groupId>\n\t\t\t<artifactId>nanohttpd</artifactId>\n\t\t\t<version>${project.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>${project.groupId}</groupId>\n\t\t\t<artifactId>nanohttpd-webserver</artifactId>\n\t\t\t<version>${project.version}</version>\n\t\t</dependency>\n\t</dependencies>\n\t<properties>\n\t\t<minimal.coverage>0.0</minimal.coverage>\n\t</properties>\n</project>\n"
  },
  {
    "path": "samples/src/main/java/org/nanohttpd/samples/http/DebugServer.java",
    "content": "package org.nanohttpd.samples.http;\n\n/*\n * #%L\n * NanoHttpd-Samples\n * %%\n * Copyright (C) 2012 - 2015 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.nanohttpd.protocols.http.IHTTPSession;\nimport org.nanohttpd.protocols.http.NanoHTTPD;\nimport org.nanohttpd.protocols.http.response.Response;\nimport org.nanohttpd.util.ServerRunner;\n\npublic class DebugServer extends NanoHTTPD {\n\n    public static void main(String[] args) {\n        ServerRunner.run(DebugServer.class);\n    }\n\n    public DebugServer() {\n        super(8080);\n    }\n\n    private void listItem(StringBuilder sb, Map.Entry<String, ? extends Object> entry) {\n        sb.append(\"<li><code><b>\").append(entry.getKey()).append(\"</b> = \").append(entry.getValue()).append(\"</code></li>\");\n    }\n\n    @Override\n    public Response serve(IHTTPSession session) {\n        Map<String, List<String>> decodedQueryParameters = decodeParameters(session.getQueryParameterString());\n\n        StringBuilder sb = new StringBuilder();\n        sb.append(\"<html>\");\n        sb.append(\"<head><title>Debug Server</title></head>\");\n        sb.append(\"<body>\");\n        sb.append(\"<h1>Debug Server</h1>\");\n\n        sb.append(\"<p><blockquote><b>URI</b> = \").append(String.valueOf(session.getUri())).append(\"<br />\");\n\n        sb.append(\"<b>Method</b> = \").append(String.valueOf(session.getMethod())).append(\"</blockquote></p>\");\n\n        sb.append(\"<h3>Headers</h3><p><blockquote>\").append(toString(session.getHeaders())).append(\"</blockquote></p>\");\n\n        sb.append(\"<h3>Parms</h3><p><blockquote>\").append(toString(session.getParms())).append(\"</blockquote></p>\");\n\n        sb.append(\"<h3>Parms (multi values?)</h3><p><blockquote>\").append(toString(decodedQueryParameters)).append(\"</blockquote></p>\");\n\n        try {\n            Map<String, String> files = new HashMap<String, String>();\n            session.parseBody(files);\n            sb.append(\"<h3>Files</h3><p><blockquote>\").append(toString(files)).append(\"</blockquote></p>\");\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n\n        sb.append(\"</body>\");\n        sb.append(\"</html>\");\n        return Response.newFixedLengthResponse(sb.toString());\n    }\n\n    private String toString(Map<String, ? extends Object> map) {\n        if (map.size() == 0) {\n            return \"\";\n        }\n        return unsortedList(map);\n    }\n\n    private String unsortedList(Map<String, ? extends Object> map) {\n        StringBuilder sb = new StringBuilder();\n        sb.append(\"<ul>\");\n        for (Map.Entry<String, ? extends Object> entry : map.entrySet()) {\n            listItem(sb, entry);\n        }\n        sb.append(\"</ul>\");\n        return sb.toString();\n    }\n}\n"
  },
  {
    "path": "samples/src/main/java/org/nanohttpd/samples/http/HelloServer.java",
    "content": "package org.nanohttpd.samples.http;\n\n/*\n * #%L\n * NanoHttpd-Samples\n * %%\n * Copyright (C) 2012 - 2015 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport java.util.Map;\nimport java.util.logging.Logger;\n\nimport org.nanohttpd.protocols.http.IHTTPSession;\nimport org.nanohttpd.protocols.http.NanoHTTPD;\nimport org.nanohttpd.protocols.http.request.Method;\nimport org.nanohttpd.protocols.http.response.Response;\nimport org.nanohttpd.util.ServerRunner;\n\n/**\n * An example of subclassing NanoHTTPD to make a custom HTTP server.\n */\npublic class HelloServer extends NanoHTTPD {\n\n    /**\n     * logger to log to.\n     */\n    private static final Logger LOG = Logger.getLogger(HelloServer.class.getName());\n\n    public static void main(String[] args) {\n        ServerRunner.run(HelloServer.class);\n    }\n\n    public HelloServer() {\n        super(8080);\n    }\n\n    @Override\n    public Response serve(IHTTPSession session) {\n        Method method = session.getMethod();\n        String uri = session.getUri();\n        HelloServer.LOG.info(method + \" '\" + uri + \"' \");\n\n        String msg = \"<html><body><h1>Hello server</h1>\\n\";\n        Map<String, String> parms = session.getParms();\n        if (parms.get(\"username\") == null) {\n            msg += \"<form action='?' method='get'>\\n\" + \"  <p>Your name: <input type='text' name='username'></p>\\n\" + \"</form>\\n\";\n        } else {\n            msg += \"<p>Hello, \" + parms.get(\"username\") + \"!</p>\";\n        }\n\n        msg += \"</body></html>\\n\";\n\n        return Response.newFixedLengthResponse(msg);\n    }\n}\n"
  },
  {
    "path": "samples/src/main/java/org/nanohttpd/samples/tempfiles/TempFilesServer.java",
    "content": "package org.nanohttpd.samples.tempfiles;\n\n/*\n * #%L\n * NanoHttpd-Samples\n * %%\n * Copyright (C) 2012 - 2015 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport java.io.File;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport org.nanohttpd.protocols.http.tempfiles.DefaultTempFile;\nimport org.nanohttpd.protocols.http.tempfiles.ITempFile;\nimport org.nanohttpd.protocols.http.tempfiles.ITempFileManager;\nimport org.nanohttpd.samples.http.DebugServer;\nimport org.nanohttpd.util.IFactory;\nimport org.nanohttpd.util.ServerRunner;\n\n/**\n * @author Paul S. Hawke (paul.hawke@gmail.com) On: 3/9/13 at 12:47 AM\n */\npublic class TempFilesServer extends DebugServer {\n\n    private static class ExampleManager implements ITempFileManager {\n\n        private final File tmpdir;\n\n        private final List<ITempFile> tempFiles;\n\n        private ExampleManager() {\n            this.tmpdir = new File(System.getProperty(\"java.io.tmpdir\"));\n            this.tempFiles = new ArrayList<ITempFile>();\n        }\n\n        @Override\n        public void clear() {\n            if (!this.tempFiles.isEmpty()) {\n                System.out.println(\"Cleaning up:\");\n            }\n            for (ITempFile file : this.tempFiles) {\n                try {\n                    System.out.println(\"   \" + file.getName());\n                    file.delete();\n                } catch (Exception ignored) {\n                }\n            }\n            this.tempFiles.clear();\n        }\n\n        @Override\n        public ITempFile createTempFile(String filename_hint) throws Exception {\n            DefaultTempFile tempFile = new DefaultTempFile(this.tmpdir);\n            this.tempFiles.add(tempFile);\n            System.out.println(\"Created tempFile: \" + tempFile.getName());\n            return tempFile;\n        }\n    }\n\n    private static class ExampleManagerFactory implements IFactory<ITempFileManager> {\n\n        @Override\n        public ITempFileManager create() {\n            return new ExampleManager();\n        }\n    }\n\n    public static void main(String[] args) {\n        TempFilesServer server = new TempFilesServer();\n        server.setTempFileManagerFactory(new ExampleManagerFactory());\n        ServerRunner.executeInstance(server);\n    }\n}\n"
  },
  {
    "path": "samples/src/site/site.xml",
    "content": "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n<project name=\"${project.name}\">\n\t<skin>\n\t\t<groupId>org.apache.maven.skins</groupId>\n\t\t<artifactId>maven-fluido-skin</artifactId>\n\t\t<version>1.3.0</version>\n\t</skin>\n\t<bannerLeft>\n\t\t<src>../images/nanohttpd_logo.png</src>\n\t</bannerLeft>\n\t<bannerRight>\n\t\t<src>../images/nanohttpd_logo_text.png</src>\n\t</bannerRight>\n\t<publishDate position=\"left\" format=\"yyyy-MM-dd\" />\n\t<version position=\"right\" />\n\t<poweredBy>\n\t\t<logo name=\"Maven\" href=\"http://maven.apache.org/\"\n\t\t\timg=\"http://maven.apache.org/images/logos/maven-feather.png\" />\n\t</poweredBy>\n\t<custom>\n\t\t<fluidoSkin>\n\t\t\t<topBarEnabled>false</topBarEnabled>\n\t\t\t<sideBarEnabled>true</sideBarEnabled>\n\t\t\t<gitHub>\n\t\t\t\t<projectId>Nanohttpd/nanohttpd</projectId>\n\t\t\t\t<ribbonOrientation>right</ribbonOrientation>\n\t\t\t\t<ribbonColor>black</ribbonColor>\n\t\t\t</gitHub>\n\t\t</fluidoSkin>\n\t</custom>\n\t<body>\n\t\t<breadcrumbs>\n\t\t\t<item name=\"${project.name}\" href=\"index.html\" />\n\t\t</breadcrumbs>\n\t\t<menu name=\"Documentation\">\n\t\t\t<item name=\"About\" href=\"index.html\" />\n\t\t</menu>\n\t\t<menu ref=\"modules\" />\n\t\t<menu ref=\"reports\" />\n\t</body>\n</project>"
  },
  {
    "path": "settings.gradle",
    "content": "rootProject.name = 'nanohttpd-project'\ninclude ':nanohttpd'\ninclude ':nanohttpd-samples'\ninclude ':nanohttpd-webserver'\ninclude ':nanohttpd-websocket'\ninclude ':nanohttpd-webserver-markdown-plugin'\ninclude ':nanohttpd-nanolets'\ninclude ':nanohttpd-apache-fileupload'\n\nproject(':nanohttpd').projectDir = \"$rootDir/core\" as File\nproject(':nanohttpd-samples').projectDir = \"$rootDir/samples\" as File\nproject(':nanohttpd-webserver').projectDir = \"$rootDir/webserver\" as File\nproject(':nanohttpd-websocket').projectDir = \"$rootDir/websocket\" as File\nproject(':nanohttpd-webserver-markdown-plugin').projectDir = \"$rootDir/markdown-plugin\" as File\nproject(':nanohttpd-nanolets').projectDir = \"$rootDir/nanolets\" as File\nproject(':nanohttpd-apache-fileupload').projectDir = \"$rootDir/fileupload\" as File"
  },
  {
    "path": "settings.xml",
    "content": "<settings>\n\t<proxies>\n\t</proxies>\n\t<servers>\n\t\t<server>\n\t\t\t<id>sonatype-nexus-staging</id>\n\t\t\t<username>${env.CI_DEPLOY_USERNAME}</username>\n\t\t\t<password>${env.CI_DEPLOY_PASSWORD}</password>\n\t\t</server>\n\t</servers>\n\t<mirrors>\n\t</mirrors>\n\t<profiles>\n\t</profiles>\n</settings>"
  },
  {
    "path": "src/main/checkstyle/checkstyle-suppressions.xml",
    "content": "<?xml version=\"1.0\"?>\n\n<!DOCTYPE suppressions PUBLIC\n     \"-//Puppy Crawl//DTD Suppressions 1.0//EN\"\n     \"http://www.puppycrawl.com/dtds/suppressions_1_0.dtd\">\n\n<suppressions>\n\n\t<suppress files=\".jpg\" checks=\"NewlineAtEndOfFile|FileTabCharacter|FileLength\" />\n\t<suppress files=\".png\" checks=\"NewlineAtEndOfFile|FileTabCharacter|FileLength\" />\n\t<suppress files=\".fxml\" checks=\"FileTabCharacter\" />\n\t<suppress files=\".css\" checks=\"FileTabCharacter\" />\n\t<suppress files=\"META[\\\\-]INF[\\\\/]services[\\\\/]\" checks=\"NewlineAtEndOfFile|FileTabCharacter\" />\n\n\t<!-- JUnit Rules require the rules field to have public visibility. -->\n\t<!-- See http://checkstyle.sourceforge.net/config_design.html#VisibilityModifier -->\n\t<suppress files=\".*Test\\.java\" checks=\"VisibilityModifier\" />\n\t<suppress files=\"Test.*\\.java\" checks=\"VisibilityModifier\" />\n\n\t<!-- For our tests we do not demand API documentation. -->\n\t<!-- See http://checkstyle.sf.net/config_javadoc.html -->\n\t<suppress files=\".*Test\\.java\" checks=\"JavadocPackage\" />\n\t<suppress files=\".*Test\\.java\" checks=\"JavadocMethod\" />\n\t<suppress files=\".*Test\\.java\" checks=\"JavadocType\" />\n\t<suppress files=\".*Test\\.java\" checks=\"JavadocVariable\" />\n\t<suppress files=\".*Test\\.java\" checks=\"JavadocStyle\" />\n\n</suppressions>"
  },
  {
    "path": "src/main/checkstyle/nanohttpd-style.xml",
    "content": "<?xml version=\"1.0\"?>\n<!DOCTYPE module PUBLIC\n          \"-//Puppy Crawl//DTD Check Configuration 1.3//EN\"\n          \"http://www.puppycrawl.com/dtds/configuration_1_3.dtd\">\n\n<!-- Checkstyle configuration that checks the sun coding conventions from: - the Java Language Specification at http://java.sun.com/docs/books/jls/second_edition/html/index.html - the \n\tSun Code Conventions at http://java.sun.com/docs/codeconv/ - the Javadoc guidelines at http://java.sun.com/j2se/javadoc/writingdoccomments/index.html - the JDK Api documentation http://java.sun.com/j2se/docs/api/index.html \n\t- some best practices Checkstyle is very configurable. Be sure to read the documentation at http://checkstyle.sf.net (or in your downloaded distribution). Most Checks are configurable, \n\tbe sure to consult the documentation. To completely disable a check, just comment it out or delete it from the file. Finally, it is worth reading the documentation. -->\n\n<module name=\"Checker\">\n\t<module name=\"SuppressionFilter\">\n    \t<property name=\"file\" value=\"${checkstyle.suppressions.file}\" default=\"src/main/checkstyle/checkstyle-suppressions.xml\"/>\n\t</module>\n\t<!-- If you set the basedir property below, then all reported file names will be relative to the specified directory. See http://checkstyle.sourceforge.net/5.x/config.html#Checker \n\t\t<property name=\"basedir\" value=\"${basedir}\"/> -->\n\n\t<!-- Checks whether files end with a new line. -->\n\t<!-- See http://checkstyle.sf.net/config_misc.html#NewlineAtEndOfFile -->\n\t<module name=\"NewlineAtEndOfFile\" />\n\n\t<!-- Checks that property files contain the same keys. -->\n\t<!-- See http://checkstyle.sf.net/config_misc.html#Translation -->\n\t<module name=\"Translation\" />\n\n\t<!-- Checks for Size Violations. -->\n\t<!-- See http://checkstyle.sf.net/config_sizes.html -->\n\t<module name=\"FileLength\" />\n\n\t<!-- Checks for whitespace -->\n\t<!-- See http://checkstyle.sf.net/config_whitespace.html -->\n\t<module name=\"FileTabCharacter\" />\n\n\n\t<!-- Checks for Headers -->\n\t<!-- See http://checkstyle.sf.net/config_header.html -->\n\t<!-- <module name=\"Header\"> -->\n\t<!-- <property name=\"headerFile\" value=\"${checkstyle.header.file}\"/> -->\n\t<!-- <property name=\"fileExtensions\" value=\"java\"/> -->\n\t<!-- </module> -->\n\n\t<module name=\"TreeWalker\">\n\n\t\t<!-- Checks for Javadoc comments. -->\n\t\t<!-- See http://checkstyle.sf.net/config_javadoc.html -->\n\t\t<module name=\"JavadocMethod\" >\n\t\t\t<property name=\"scope\" value=\"protected\" />\n\t\t</module>\n\t\t<module name=\"JavadocType\" >\n\t\t\t<property name=\"scope\" value=\"protected\" />\n\t\t</module>\n\t\t<module name=\"JavadocVariable\" >\n\t\t\t<property name=\"scope\" value=\"protected\" />\n\t\t</module>\n\t\t<module name=\"JavadocStyle\" >\n\t\t\t<property name=\"scope\" value=\"protected\" />\n\t\t</module>\n\n\n\t\t<!-- Checks for Naming Conventions. -->\n\t\t<!-- See http://checkstyle.sf.net/config_naming.html -->\n\t\t<module name=\"ConstantName\" />\n\t\t<module name=\"LocalFinalVariableName\" />\n\t\t<module name=\"LocalVariableName\" />\n\t\t<module name=\"MemberName\" />\n\t\t<module name=\"MethodName\" />\n\t\t<module name=\"PackageName\" />\n\t\t<module name=\"ParameterName\" />\n\t\t<module name=\"StaticVariableName\" />\n\t\t<module name=\"TypeName\" />\n\n\n\t\t<!-- Checks for imports -->\n\t\t<!-- See http://checkstyle.sf.net/config_import.html -->\n\t\t<module name=\"AvoidStarImport\" />\n\t\t<module name=\"IllegalImport\" /> <!-- defaults to sun.* packages -->\n\t\t<module name=\"RedundantImport\" />\n\t\t<module name=\"UnusedImports\" />\n\n\n\t\t<!-- Checks for Size Violations. -->\n\t\t<!-- See http://checkstyle.sf.net/config_sizes.html -->\n\t\t<module name=\"LineLength\">\n\t\t\t<property name=\"max\" value=\"180\" />\n\t\t</module>\n\t\t<module name=\"MethodLength\" />\n\t\t<module name=\"ParameterNumber\" />\n\n\n\t\t<!-- Checks for whitespace -->\n\t\t<!-- See http://checkstyle.sf.net/config_whitespace.html -->\n\t\t<module name=\"EmptyForIteratorPad\" />\n\t\t<module name=\"GenericWhitespace\" />\n\t\t<module name=\"MethodParamPad\" />\n\t\t<module name=\"NoWhitespaceAfter\" />\n\t\t<module name=\"NoWhitespaceBefore\" />\n\t\t<module name=\"OperatorWrap\" />\n\t\t<module name=\"ParenPad\" />\n\t\t<module name=\"TypecastParenPad\" />\n\t\t<module name=\"WhitespaceAfter\" />\n\t\t<module name=\"WhitespaceAround\" />\n\n\n\t\t<!-- Modifier Checks -->\n\t\t<!-- See http://checkstyle.sf.net/config_modifiers.html -->\n\t\t<module name=\"ModifierOrder\" />\n\t\t<module name=\"RedundantModifier\" />\n\n\n\t\t<!-- Checks for blocks. You know, those {}'s -->\n\t\t<!-- See http://checkstyle.sf.net/config_blocks.html -->\n\t\t<module name=\"AvoidNestedBlocks\" />\n\t\t<module name=\"EmptyBlock\" />\n\t\t<module name=\"LeftCurly\" />\n\t\t<module name=\"NeedBraces\" />\n\t\t<module name=\"RightCurly\" />\n\n\n\t\t<!-- Checks for common coding problems -->\n\t\t<!-- See http://checkstyle.sf.net/config_coding.html -->\n\t\t<!-- <module name=\"AvoidInlineConditionals\" /> i think simple cases are ok, not generally bad -->\n\t\t<module name=\"EmptyStatement\" />\n\t\t<module name=\"EqualsHashCode\" />\n\t\t<module name=\"HiddenField\">\n\t\t\t<property name=\"ignoreSetter\" value=\"true\" />\n\t\t\t<property name=\"ignoreConstructorParameter\" value=\"true\" />\n\t\t</module>\n\t\t<module name=\"IllegalInstantiation\" />\n\t\t<module name=\"InnerAssignment\" />\n\n\t\t<module name=\"MissingSwitchDefault\" />\n\t\t<module name=\"RedundantThrows\">\n\t\t\t<property name=\"suppressLoadErrors\" value=\"true\" />\n\t\t</module>\n\t\t<module name=\"SimplifyBooleanExpression\" />\n\t\t<module name=\"SimplifyBooleanReturn\" />\n\n\t\t<!-- Checks for class design -->\n\t\t<!-- See http://checkstyle.sf.net/config_design.html -->\n\t\t<!-- <module name=\"DesignForExtension\" /> part of this would be good but it goes to much to the core -->\n\t\t<module name=\"FinalClass\" />\n\t\t<module name=\"HideUtilityClassConstructor\" />\n\t\t<module name=\"InterfaceIsType\" />\n\t\t<module name=\"VisibilityModifier\">\n\t\t\t<property name=\"protectedAllowed\" value=\"true\" />\n\t\t</module>\n\n\n\t\t<!-- Miscellaneous other checks. -->\n\t\t<!-- See http://checkstyle.sf.net/config_misc.html -->\n\t\t<module name=\"ArrayTypeStyle\" />\n\t\t<!-- <module name=\"TodoComment\" /> is better done by the taglist plugin -->\n\t\t<module name=\"UpperEll\" />\n\n\t</module>\n\n</module>\n"
  },
  {
    "path": "src/main/formatter/formatter.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<profiles version=\"11\">\n<profile kind=\"CodeFormatterProfile\" name=\"CFC\" version=\"11\">\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_enum_constant\" value=\"end_of_line\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_semicolon\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.align_type_members_on_columns\" value=\"false\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.comment.format_line_comments\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve\" value=\"1\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations\" value=\"1\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.indent_statements_compare_to_body\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_member\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line\" value=\"false\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.tabulation.size\" value=\"4\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.blank_lines_before_imports\" value=\"1\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk\" value=\"1\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.continuation_indentation\" value=\"2\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_binary_operator\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration\" value=\"16\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_assignment\" value=\"16\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.blank_lines_before_member_type\" value=\"1\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_conditional_expression\" value=\"16\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.comment.indent_parameter_description\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.comment.format_html\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.comment.format_source_code\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_unary_operator\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.indentation.size\" value=\"4\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration\" value=\"16\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration\" value=\"end_of_line\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.lineSplit\" value=\"175\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_array_initializer\" value=\"end_of_line\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration\" value=\"16\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.comment.format_header\" value=\"false\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call\" value=\"16\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_multiple_fields\" value=\"16\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line\" value=\"false\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_binary_operator\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer\" value=\"49\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_method_declaration\" value=\"end_of_line\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.blank_lines_before_field\" value=\"1\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration\" value=\"16\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.comment.format_javadoc_comments\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.comment.format_block_comments\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_binary_expression\" value=\"16\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.wrap_before_binary_operator\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.blank_lines_after_package\" value=\"1\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration\" value=\"16\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode\" value=\"enabled\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.blank_lines_between_import_groups\" value=\"1\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_ellipsis\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration\" value=\"end_of_line\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression\" value=\"16\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.blank_lines_after_imports\" value=\"1\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.compiler.problem.assertIdentifier\" value=\"error\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant\" value=\"16\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_block_in_case\" value=\"end_of_line\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration\" value=\"end_of_line\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration\" value=\"1\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line\" value=\"false\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.indent_empty_lines\" value=\"false\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.compiler.source\" value=\"1.5\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.comment.line_length\" value=\"80\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_type_declaration\" value=\"end_of_line\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.compiler.compliance\" value=\"1.5\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.compact_else_if\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations\" value=\"false\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_switch\" value=\"end_of_line\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration\" value=\"16\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body\" value=\"0\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.compiler.problem.enumIdentifier\" value=\"error\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line\" value=\"false\"/>\n<setting id=\"org.eclipse.jdt.core.compiler.codegen.targetPlatform\" value=\"1.5\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_compact_if\" value=\"16\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_ellipsis\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression\" value=\"16\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.indent_statements_compare_to_block\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line\" value=\"false\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration\" value=\"end_of_line\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation\" value=\"16\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column\" value=\"false\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_unary_operator\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer\" value=\"1\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.comment.indent_root_tags\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_enum_constants\" value=\"49\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration\" value=\"16\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation\" value=\"16\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.tabulation.char\" value=\"space\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.blank_lines_before_package\" value=\"0\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line\" value=\"true\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.blank_lines_before_method\" value=\"1\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column\" value=\"false\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.brace_position_for_block\" value=\"end_of_line\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer\" value=\"insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression\" value=\"do not insert\"/>\n<setting id=\"org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter\" value=\"insert\"/>\n</profile>\n</profiles>\n"
  },
  {
    "path": "src/site/markdown/index.md",
    "content": "## NanoHTTPD – a tiny web server in Java\n\n*NanoHTTPD* is a light-weight HTTP server designed for embedding in other applications, released under a Modified BSD licence.\n\nIt is being developed at Github and uses Apache Maven for builds & unit testing:\n\n * Build status: [![Build Status](https://api.travis-ci.org/NanoHttpd/nanohttpd.png)](https://travis-ci.org/NanoHttpd/nanohttpd)\n * Coverage Status: [![Coverage Status](https://coveralls.io/repos/NanoHttpd/nanohttpd/badge.svg)](https://coveralls.io/r/NanoHttpd/nanohttpd)\n * Current central released version: [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.nanohttpd/nanohttpd/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.nanohttpd/nanohttpd)\n\n## Quickstart\n\nWe'll create a custom HTTP server project using Maven for build/dep system. This tutorial assumes you are using a Unix variant and a shell. First, install Maven and Java SDK if not already installed. Then run:\n\n    mvn compile\n    mvn exec:java -pl webserver -Dexec.mainClass=\"fi.iki.elonen.SimpleWebServer\"\n    \nYou should now have a HTTP file server running on <http://localhost:8080/>.\n\n### Custom web app\n\nLet's raise the bar and build a custom web application next:\n\n    mvn archetype:generate -DgroupId=com.example -DartifactId=myHellopApp -DinteractiveMode=false\n    cd myHellopApp\n    \nEdit `pom.xml`, and add this between \\<dependencies\\>:\n \n\t<dependency>\n\t\t<groupId>org.nanohttpd</groupId> <!-- <groupId>com.nanohttpd</groupId> for 2.1.0 and earlier -->\n\t\t<artifactId>nanohttpd</artifactId>\n\t\t<version>2.2.0</version>\n\t</dependency>\n\t\nEdit `src/main/java/com/example/App.java` and replace it with:\n```java\n    package com.example;\n    \n    import java.io.IOException;\n    import java.util.Map;\n    \n    import fi.iki.elonen.NanoHTTPD;\n    \n    public class App extends NanoHTTPD {\n    \n        public App() throws IOException {\n            super(8080);\n            start(NanoHTTPD.SOCKET_READ_TIMEOUT, false);\n            System.out.println(\"\\nRunning! Point your browers to http://localhost:8080/ \\n\");\n        }\n    \n        public static void main(String[] args) {\n            try {\n                new App();\n            } catch (IOException ioe) {\n                System.err.println(\"Couldn't start server:\\n\" + ioe);\n            }\n        }\n    \n        @Override\n        public Response serve(IHTTPSession session) {\n            String msg = \"<html><body><h1>Hello server</h1>\\n\";\n            Map<String, String> parms = session.getParms();\n            if (parms.get(\"username\") == null) {\n                msg += \"<form action='?' method='get'>\\n  <p>Your name: <input type='text' name='username'></p>\\n\" + \"</form>\\n\";\n            } else {\n                msg += \"<p>Hello, \" + parms.get(\"username\") + \"!</p>\";\n            }\n            return newFixedLengthResponse(msg + \"</body></html>\\n\");\n        }\n    }\n```\n\nCompile and run the server:\n \n    mvn compile\n    mvn exec:java -Dexec.mainClass=\"com.example.App\"\n    \nIf it started ok, point your browser at <http://localhost:8080/> and enjoy a web server that asks your name and replies with a greeting. \n\n### Nanolets\n\nNanolets are like sevlet's only that they have a extrem low profile. They offer an easy to use system for a more complex server application. \nThis text has to be extrended with an example, so for now take a look at the unit tests for the usage. <https://github.com/NanoHttpd/nanohttpd/blob/master/nanolets/src/test/java/fi/iki/elonen/router/AppNanolets.java>\n\n## Status\n\nWe are currently in the process of stabilizing NanoHttpd from the many pull requests and feature requests that were integrated over the last few months. The next release will come soon, and there will not be any more \"intended\" major changes before the next release. If you want to use the bleeding edge version, you can clone it from Github, or get it from sonatype.org (see \"Maven dependencies / Living on the edge\" below).\n\n## Project structure\n\nNanoHTTPD project currently consist of four parts:\n\n * `/core` – Fully functional HTTP(s) server consisting of one (1) Java file, ready to be customized/inherited for your own project\n\n * `/samples` – Simple examples on how to customize NanoHTTPD. See *HelloServer.java* for a killer app that greets you enthusiastically!\n\n * `/websocket` – Websocket implementation, also in a single Java file. Depends on core.\n\n * `/webserver` – Standalone file server. Run & enjoy. A popular use seems to be serving files out off an Android device.\n\n * `/nanolets` – Standalone nano app server, giving a servlet like system to the implementor.\n\n * `/fileupload` – integration of the apache common file upload library.\n\n## Features\n### Core\n* Only one Java file, providing HTTP 1.1 support.\n* No fixed config files, logging, authorization etc. (Implement by yourself if you need them. Errors are passed to java.util.logging, though.)\n* Support for HTTPS (SSL)\n* Basic support for cookies\n* Supports parameter parsing of GET and POST methods.\n* Some built-in support for HEAD, POST and DELETE requests. You can easily implement/customize any HTTP method, though.\n* Supports file upload. Uses memory for small uploads, temp files for large ones.\n* Never caches anything.\n* Does not limit bandwidth, request time or simultaneous connections by default.\n* All header names are converted to lower case so they don't vary between browsers/clients.\n* Persistent connections (Connection \"keep-alive\") support allowing multiple requests to be served over a single socket connection.\n\n### Websocket\n* Tested on Firefox, Chrome and IE.\n\n### Webserver\n* Default code serves files and shows (prints on console) all HTTP parameters and headers.\n* Supports both dynamic content and file serving.\n* File server supports directory listing, `index.html` and `index.htm`.\n* File server supports partial content (streaming & continue download).\n* File server supports ETags.\n* File server does the 301 redirection trick for directories without `/`.\n* File server serves also very long files without memory overhead.\n* Contains a built-in list of most common MIME types.\n* Runtime extension support (extensions that serve particular MIME types) - example extension that serves Markdown formatted files. Simply including an extension JAR in the webserver classpath is enough for the extension to be loaded.\n* Simple [CORS](https://en.wikipedia.org/wiki/Cross-origin_resource_sharing) support via `--cors` paramater\n  * by default serves `Access-Control-Allow-Headers: origin,accept,content-type`\n  * possibility to set `Access-Control-Allow-Headers` by setting System property: `AccessControlAllowHeader`\n  * _example: _ `-DAccessControlAllowHeader=origin,accept,content-type,Authorization`\n  * possible values:\n      * `--cors`: activates CORS support, `Access-Control-Allow-Origin` will be set to `*`\n      * `--cors=some_value`: `Access-Control-Allow-Origin` will be set to `some_value`. \n\n**_CORS argument examples_**\n\n\n* `--cors=http://appOne.company.com`\n* `--cors=\"http://appOne.company.com, http://appTwo.company.com\"`: note the double quotes so that the 2 URLs are considered part of a single argument.\n\n## Maven dependencies\n\nNanoHTTPD is a Maven based project and deployed to central. Most development environments have means to access the central repository. The coordinates to use in Maven are: \n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>org.nanohttpd</groupId> <!-- <groupId>com.nanohttpd</groupId> for 2.1.0 and earlier -->\n\t\t\t<artifactId>nanohttpd</artifactId>\n\t\t\t<version>2.2.0</version>\n\t\t</dependency>\n\t</dependencies>\n\nThe coordinates for your development environment should correspond to these. When looking for an older version take care because we switched groupId from *com.nanohttpd* to *org.nanohttpd* in mid 2015.\n\nNext it depends what you are useing nanohttpd for, there are tree main usages.\n\n## Gradle dependencies\n\nIn gradle you can use nano http the same way because gradle accesses the same central repository:\n\n\tdependencies {\n\t\truntime(\n\t\t\t[group: 'org.nanohttpd', name: 'nanohttpd', version: '2.2.0'],\n\t\t)\n\t}\n\nJust replace the name with the artifact id of the module you want to use and gradle will find it for you. \n\n### Develop your own specialized HTTP service\n\nFor a specialized HTTP (HTTPS) service you can use the module with artifactId *nanohttpd*.\n\n\t\t<dependency>\n\t\t\t<groupId>org.nanohttpd</groupId> <!-- <groupId>com.nanohttpd</groupId> for 2.1.0 and earlier -->\n\t\t\t<artifactId>nanohttpd</artifactId>\n\t\t\t<version>2.2.0VERSION</version>\n\t\t</dependency>\n\t\t\nHere you write your own subclass of *fi.iki.elonen.NanoHTTPD* to configure and to serve the requests.\n  \n### Develop a websocket based service    \n\nFor a specialized websocket service you can use the module with artifactId *nanohttpd-websocket*.\n\n\t\t<dependency>\n\t\t\t<groupId>org.nanohttpd</groupId> <!-- <groupId>com.nanohttpd</groupId> for 2.1.0 and earlier -->\n\t\t\t<artifactId>nanohttpd-websocket</artifactId>\n\t\t\t<version>2.2.0</version>\n\t\t</dependency>\n\nHere you write your own subclass of *fi.iki.elonen.NanoWebSocketServer* to configure and to serve the websocket requests. A small standard echo example is included as *fi.iki.elonen.samples.echo.DebugWebSocketServer*. You can use it as a starting point to implement your own services.\n\n### Develop a custom HTTP file server    \n\nFor a more classic aproach, perhaps to just create a HTTP server serving mostly service files from your disk, you can use the module with artifactId *nanohttpd-webserver*.\n\n\t\t<dependency>\n\t\t\t<groupId>org.nanohttpd</groupId>\n\t\t\t<artifactId>nanohttpd-webserver</artifactId>\n\t\t\t<version>2.2.0</version>\n\t\t</dependency>\n\nThe included class *fi.iki.elonen.SimpleWebServer* is intended to be used as a starting point for your own implementation but it also can be used as is. Staring the class as is will start a http server on port 8080 and publishing the current directory.  \n\n### Living on the edge\n\nThe latest Github master version can be fetched through sonatype.org:\n\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<artifactId>nanohttpd</artifactId>\n\t\t\t<groupId>org.nanohttpd</groupId>\n\t\t\t<version>XXXXX-SNAPSHOT</version>\n\t\t</dependency>\n\t</dependencies>\n\t...\n\t<repositories>\n\t\t<repository>\n\t\t\t<id>sonatype-snapshots</id>\n\t\t\t<url>https://oss.sonatype.org/content/repositories/snapshots</url>\n\t\t\t<snapshots>\n\t\t\t\t<enabled>true</enabled>\n\t\t\t</snapshots>\n\t\t</repository>\n\t</repositories>\n\n### generating an self signed ssl certificate\n\nJust a hint how to generate a certificate for localhost.\n\n\tkeytool -genkey -keyalg RSA -alias selfsigned -keystore keystore.jks -storepass password -validity 360 -keysize 2048 -ext SAN=DNS:localhost,IP:127.0.0.1  -validity 9999\n\nThis will generate a keystore file named 'keystore.jks' with a self signed certificate for a host named localhost with the ip adress 127.0.0.1 . Now \nyou can use:\n\n\tserver.makeSecure(NanoHTTPD.makeSSLSocketFactory(\"/keystore.jks\", \"password\".toCharArray()), null);\n\nBefore you start the server to make Nanohttpd serve https connections, when you make sure 'keystore.jks' is in your classpath .  \n \n-----\n\n*Thank you to everyone who has reported bugs and suggested fixes.*\n"
  },
  {
    "path": "src/site/site.xml",
    "content": "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n<project name=\"${project.name}\">\n\t<skin>\n\t\t<groupId>org.apache.maven.skins</groupId>\n\t\t<artifactId>maven-fluido-skin</artifactId>\n\t\t<version>1.3.0</version>\n\t</skin>\n\t<bannerLeft>\n\t\t<src>images/nanohttpd_logo.png</src>\n\t</bannerLeft>\n\t<bannerRight>\n\t\t<src>images/nanohttpd_logo_text.png</src>\n\t</bannerRight>\n\t<publishDate position=\"left\" format=\"yyyy-MM-dd\" />\n\t<version position=\"right\" />\n\t<poweredBy>\n\t\t<logo name=\"Maven\" href=\"http://maven.apache.org/\" img=\"http://maven.apache.org/images/logos/maven-feather.png\" />\n\t</poweredBy>\n\t<custom>\n\t\t<fluidoSkin>\n\t\t\t<topBarEnabled>false</topBarEnabled>\n\t\t\t<sideBarEnabled>true</sideBarEnabled>\n\t\t\t<gitHub>\n\t\t\t\t<projectId>Nanohttpd/nanohttpd</projectId>\n\t\t\t\t<ribbonOrientation>right</ribbonOrientation>\n\t\t\t\t<ribbonColor>black</ribbonColor>\n\t\t\t</gitHub>\n\t\t</fluidoSkin>\n\t</custom>\n\t<body>\n\t\t<breadcrumbs>\n\t\t\t<item name=\"${project.name}\" href=\"index.html\" />\n\t\t</breadcrumbs>\n\t\t<menu name=\"Documentation\">\n\t\t\t<item name=\"About\" href=\"index.html\" />\n\t\t</menu>\n\t\t<menu ref=\"modules\" />\n\t\t<menu ref=\"reports\" />\n\t</body>\n</project>"
  },
  {
    "path": "webserver/.gitignore",
    "content": "/.settings/\n/LICENSE.txt\n"
  },
  {
    "path": "webserver/build.gradle",
    "content": "description = 'NanoHttpd-Webserver'\n\ndependencies {\n\tcompile project(':nanohttpd')\n\t\n\ttestCompile group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.4.1'\n}\n\ntask wrapper(type: Wrapper) {\n\tgradleVersion = \"4.4.1\"\n}\n"
  },
  {
    "path": "webserver/pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<parent>\n\t\t<groupId>org.nanohttpd</groupId>\n\t\t<artifactId>nanohttpd-project</artifactId>\n\t\t<version>2.3.2-SNAPSHOT</version>\n\t</parent>\n\t<artifactId>nanohttpd-webserver</artifactId>\n\t<packaging>jar</packaging>\n\t<name>NanoHttpd-Webserver</name>\n\t<description>nanohttpd-webserver can serve any local directory as a webserver using nanohttpd.</description>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>${project.groupId}</groupId>\n\t\t\t<artifactId>nanohttpd</artifactId>\n\t\t\t<version>${project.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.apache.httpcomponents</groupId>\n\t\t\t<artifactId>httpclient</artifactId>\n\t\t\t<version>4.4.1</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t</dependencies>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-assembly-plugin</artifactId>\n\t\t\t\t<version>2.2-beta-5</version>\n\t\t\t\t<configuration>\n\t\t\t\t\t<descriptorRefs>\n\t\t\t\t\t\t<descriptorRef>jar-with-dependencies</descriptorRef>\n\t\t\t\t\t</descriptorRefs>\n\t\t\t\t\t<archive>\n\t\t\t\t\t\t<manifest>\n\t\t\t\t\t\t\t<mainClass>fi.iki.elonen.SimpleWebServer</mainClass>\n\t\t\t\t\t\t</manifest>\n\t\t\t\t\t</archive>\n\t\t\t\t</configuration>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<phase>package</phase>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>single</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<properties>\n\t\t<minimal.coverage>0.75</minimal.coverage>\n\t</properties>\n</project>\n"
  },
  {
    "path": "webserver/src/main/java/org/nanohttpd/webserver/InternalRewrite.java",
    "content": "package org.nanohttpd.webserver;\n\n/*\n * #%L\n * NanoHttpd-Webserver\n * %%\n * Copyright (C) 2012 - 2015 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport java.io.ByteArrayInputStream;\nimport java.util.Map;\n\nimport org.nanohttpd.protocols.http.NanoHTTPD;\nimport org.nanohttpd.protocols.http.response.Response;\nimport org.nanohttpd.protocols.http.response.Status;\n\n/**\n * @author Paul S. Hawke (paul.hawke@gmail.com) On: 9/15/13 at 2:52 PM\n */\npublic class InternalRewrite extends Response {\n\n    private final String uri;\n\n    private final Map<String, String> headers;\n\n    public InternalRewrite(Map<String, String> headers, String uri) {\n        super(Status.OK, NanoHTTPD.MIME_HTML, new ByteArrayInputStream(new byte[0]), 0);\n        this.headers = headers;\n        this.uri = uri;\n    }\n\n    public Map<String, String> getHeaders() {\n        return this.headers;\n    }\n\n    public String getUri() {\n        return this.uri;\n    }\n}\n"
  },
  {
    "path": "webserver/src/main/java/org/nanohttpd/webserver/SimpleWebServer.java",
    "content": "package org.nanohttpd.webserver;\n\n/*\n * #%L\n * NanoHttpd-Webserver\n * %%\n * Copyright (C) 2012 - 2015 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.FilenameFilter;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.UnsupportedEncodingException;\nimport java.net.URLEncoder;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.ServiceLoader;\nimport java.util.StringTokenizer;\n\nimport org.nanohttpd.protocols.http.IHTTPSession;\nimport org.nanohttpd.protocols.http.NanoHTTPD;\nimport org.nanohttpd.protocols.http.request.Method;\nimport org.nanohttpd.protocols.http.response.IStatus;\nimport org.nanohttpd.protocols.http.response.Response;\nimport org.nanohttpd.protocols.http.response.Status;\nimport org.nanohttpd.util.ServerRunner;\n\npublic class SimpleWebServer extends NanoHTTPD {\n\n    /**\n     * Default Index file names.\n     */\n    @SuppressWarnings(\"serial\")\n    public static final List<String> INDEX_FILE_NAMES = new ArrayList<String>() {\n\n        {\n            add(\"index.html\");\n            add(\"index.htm\");\n        }\n    };\n\n    /**\n     * The distribution licence\n     */\n    private static final String LICENCE;\n    static {\n        mimeTypes();\n        String text;\n        try {\n            InputStream stream = SimpleWebServer.class.getResourceAsStream(\"/LICENSE.txt\");\n            ByteArrayOutputStream bytes = new ByteArrayOutputStream();\n            byte[] buffer = new byte[1024];\n            int count;\n            while ((count = stream.read(buffer)) >= 0) {\n                bytes.write(buffer, 0, count);\n            }\n            text = bytes.toString(\"UTF-8\");\n        } catch (Exception e) {\n            text = \"unknown\";\n        }\n        LICENCE = text;\n    }\n\n    private static Map<String, WebServerPlugin> mimeTypeHandlers = new HashMap<String, WebServerPlugin>();\n\n    /**\n     * Starts as a standalone file server and waits for Enter.\n     */\n    public static void main(String[] args) {\n        // Defaults\n        int port = 8080;\n\n        String host = null; // bind to all interfaces by default\n        List<File> rootDirs = new ArrayList<File>();\n        boolean quiet = false;\n        String cors = null;\n        Map<String, String> options = new HashMap<String, String>();\n\n        // Parse command-line, with short and long versions of the options.\n        for (int i = 0; i < args.length; ++i) {\n            if (\"-h\".equalsIgnoreCase(args[i]) || \"--host\".equalsIgnoreCase(args[i])) {\n                host = args[i + 1];\n            } else if (\"-p\".equalsIgnoreCase(args[i]) || \"--port\".equalsIgnoreCase(args[i])) {\n                port = Integer.parseInt(args[i + 1]);\n            } else if (\"-q\".equalsIgnoreCase(args[i]) || \"--quiet\".equalsIgnoreCase(args[i])) {\n                quiet = true;\n            } else if (\"-d\".equalsIgnoreCase(args[i]) || \"--dir\".equalsIgnoreCase(args[i])) {\n                rootDirs.add(new File(args[i + 1]).getAbsoluteFile());\n            } else if (args[i].startsWith(\"--cors\")) {\n                cors = \"*\";\n                int equalIdx = args[i].indexOf('=');\n                if (equalIdx > 0) {\n                    cors = args[i].substring(equalIdx + 1);\n                }\n            } else if (\"--licence\".equalsIgnoreCase(args[i])) {\n                System.out.println(SimpleWebServer.LICENCE + \"\\n\");\n            } else if (args[i].startsWith(\"-X:\")) {\n                int dot = args[i].indexOf('=');\n                if (dot > 0) {\n                    String name = args[i].substring(0, dot);\n                    String value = args[i].substring(dot + 1, args[i].length());\n                    options.put(name, value);\n                }\n            }\n        }\n\n        if (rootDirs.isEmpty()) {\n            rootDirs.add(new File(\".\").getAbsoluteFile());\n        }\n        options.put(\"host\", host);\n        options.put(\"port\", \"\" + port);\n        options.put(\"quiet\", String.valueOf(quiet));\n        StringBuilder sb = new StringBuilder();\n        for (File dir : rootDirs) {\n            if (sb.length() > 0) {\n                sb.append(\":\");\n            }\n            try {\n                sb.append(dir.getCanonicalPath());\n            } catch (IOException ignored) {\n            }\n        }\n        options.put(\"home\", sb.toString());\n        ServiceLoader<WebServerPluginInfo> serviceLoader = ServiceLoader.load(WebServerPluginInfo.class);\n        for (WebServerPluginInfo info : serviceLoader) {\n            String[] mimeTypes = info.getMimeTypes();\n            for (String mime : mimeTypes) {\n                String[] indexFiles = info.getIndexFilesForMimeType(mime);\n                if (!quiet) {\n                    System.out.print(\"# Found plugin for Mime type: \\\"\" + mime + \"\\\"\");\n                    if (indexFiles != null) {\n                        System.out.print(\" (serving index files: \");\n                        for (String indexFile : indexFiles) {\n                            System.out.print(indexFile + \" \");\n                        }\n                    }\n                    System.out.println(\").\");\n                }\n                registerPluginForMimeType(indexFiles, mime, info.getWebServerPlugin(mime), options);\n            }\n        }\n        ServerRunner.executeInstance(new SimpleWebServer(host, port, rootDirs, quiet, cors));\n    }\n\n    protected static void registerPluginForMimeType(String[] indexFiles, String mimeType, WebServerPlugin plugin, Map<String, String> commandLineOptions) {\n        if (mimeType == null || plugin == null) {\n            return;\n        }\n\n        if (indexFiles != null) {\n            for (String filename : indexFiles) {\n                int dot = filename.lastIndexOf('.');\n                if (dot >= 0) {\n                    String extension = filename.substring(dot + 1).toLowerCase();\n                    mimeTypes().put(extension, mimeType);\n                }\n            }\n            SimpleWebServer.INDEX_FILE_NAMES.addAll(Arrays.asList(indexFiles));\n        }\n        SimpleWebServer.mimeTypeHandlers.put(mimeType, plugin);\n        plugin.initialize(commandLineOptions);\n    }\n\n    private final boolean quiet;\n\n    private final String cors;\n\n    protected List<File> rootDirs;\n\n    public SimpleWebServer(String host, int port, File wwwroot, boolean quiet, String cors) {\n        this(host, port, Collections.singletonList(wwwroot), quiet, cors);\n    }\n\n    public SimpleWebServer(String host, int port, File wwwroot, boolean quiet) {\n        this(host, port, Collections.singletonList(wwwroot), quiet, null);\n    }\n\n    public SimpleWebServer(String host, int port, List<File> wwwroots, boolean quiet) {\n        this(host, port, wwwroots, quiet, null);\n    }\n\n    public SimpleWebServer(String host, int port, List<File> wwwroots, boolean quiet, String cors) {\n        super(host, port);\n        this.quiet = quiet;\n        this.cors = cors;\n        this.rootDirs = new ArrayList<File>(wwwroots);\n\n        init();\n    }\n\n    private boolean canServeUri(String uri, File homeDir) {\n        boolean canServeUri;\n        File f = new File(homeDir, uri);\n        canServeUri = f.exists();\n        if (!canServeUri) {\n            WebServerPlugin plugin = SimpleWebServer.mimeTypeHandlers.get(getMimeTypeForFile(uri));\n            if (plugin != null) {\n                canServeUri = plugin.canServeUri(uri, homeDir);\n            }\n        }\n        return canServeUri;\n    }\n\n    /**\n     * URL-encodes everything between \"/\"-characters. Encodes spaces as '%20'\n     * instead of '+'.\n     */\n    private String encodeUri(String uri) {\n        String newUri = \"\";\n        StringTokenizer st = new StringTokenizer(uri, \"/ \", true);\n        while (st.hasMoreTokens()) {\n            String tok = st.nextToken();\n            if (\"/\".equals(tok)) {\n                newUri += \"/\";\n            } else if (\" \".equals(tok)) {\n                newUri += \"%20\";\n            } else {\n                try {\n                    newUri += URLEncoder.encode(tok, \"UTF-8\");\n                } catch (UnsupportedEncodingException ignored) {\n                }\n            }\n        }\n        return newUri;\n    }\n\n    private String findIndexFileInDirectory(File directory) {\n        for (String fileName : SimpleWebServer.INDEX_FILE_NAMES) {\n            File indexFile = new File(directory, fileName);\n            if (indexFile.isFile()) {\n                return fileName;\n            }\n        }\n        return null;\n    }\n\n    protected Response getForbiddenResponse(String s) {\n        return Response.newFixedLengthResponse(Status.FORBIDDEN, NanoHTTPD.MIME_PLAINTEXT, \"FORBIDDEN: \" + s);\n    }\n\n    protected Response getInternalErrorResponse(String s) {\n        return Response.newFixedLengthResponse(Status.INTERNAL_ERROR, NanoHTTPD.MIME_PLAINTEXT, \"INTERNAL ERROR: \" + s);\n    }\n\n    protected Response getNotFoundResponse() {\n        return Response.newFixedLengthResponse(Status.NOT_FOUND, NanoHTTPD.MIME_PLAINTEXT, \"Error 404, file not found.\");\n    }\n\n    /**\n     * Used to initialize and customize the server.\n     */\n    public void init() {\n    }\n\n    protected String listDirectory(String uri, File f) {\n        String heading = \"Directory \" + uri;\n        StringBuilder msg =\n                new StringBuilder(\"<html><head><title>\" + heading + \"</title><style><!--\\n\" + \"span.dirname { font-weight: bold; }\\n\" + \"span.filesize { font-size: 75%; }\\n\"\n                        + \"// -->\\n\" + \"</style>\" + \"</head><body><h1>\" + heading + \"</h1>\");\n\n        String up = null;\n        if (uri.length() > 1) {\n            String u = uri.substring(0, uri.length() - 1);\n            int slash = u.lastIndexOf('/');\n            if (slash >= 0 && slash < u.length()) {\n                up = uri.substring(0, slash + 1);\n            }\n        }\n\n        List<String> files = Arrays.asList(f.list(new FilenameFilter() {\n\n            @Override\n            public boolean accept(File dir, String name) {\n                return new File(dir, name).isFile();\n            }\n        }));\n        Collections.sort(files);\n        List<String> directories = Arrays.asList(f.list(new FilenameFilter() {\n\n            @Override\n            public boolean accept(File dir, String name) {\n                return new File(dir, name).isDirectory();\n            }\n        }));\n        Collections.sort(directories);\n        if (up != null || directories.size() + files.size() > 0) {\n            msg.append(\"<ul>\");\n            if (up != null || directories.size() > 0) {\n                msg.append(\"<section class=\\\"directories\\\">\");\n                if (up != null) {\n                    msg.append(\"<li><a rel=\\\"directory\\\" href=\\\"\").append(up).append(\"\\\"><span class=\\\"dirname\\\">..</span></a></li>\");\n                }\n                for (String directory : directories) {\n                    String dir = directory + \"/\";\n                    msg.append(\"<li><a rel=\\\"directory\\\" href=\\\"\").append(encodeUri(uri + dir)).append(\"\\\"><span class=\\\"dirname\\\">\").append(dir).append(\"</span></a></li>\");\n                }\n                msg.append(\"</section>\");\n            }\n            if (files.size() > 0) {\n                msg.append(\"<section class=\\\"files\\\">\");\n                for (String file : files) {\n                    msg.append(\"<li><a href=\\\"\").append(encodeUri(uri + file)).append(\"\\\"><span class=\\\"filename\\\">\").append(file).append(\"</span></a>\");\n                    File curFile = new File(f, file);\n                    long len = curFile.length();\n                    msg.append(\"&nbsp;<span class=\\\"filesize\\\">(\");\n                    if (len < 1024) {\n                        msg.append(len).append(\" bytes\");\n                    } else if (len < 1024 * 1024) {\n                        msg.append(len / 1024).append(\".\").append(len % 1024 / 10 % 100).append(\" KB\");\n                    } else {\n                        msg.append(len / (1024 * 1024)).append(\".\").append(len % (1024 * 1024) / 10000 % 100).append(\" MB\");\n                    }\n                    msg.append(\")</span></li>\");\n                }\n                msg.append(\"</section>\");\n            }\n            msg.append(\"</ul>\");\n        }\n        msg.append(\"</body></html>\");\n        return msg.toString();\n    }\n\n    public static Response newFixedLengthResponse(IStatus status, String mimeType, String message) {\n        Response response = Response.newFixedLengthResponse(status, mimeType, message);\n        response.addHeader(\"Accept-Ranges\", \"bytes\");\n        return response;\n    }\n\n    private Response respond(Map<String, String> headers, IHTTPSession session, String uri) {\n        // First let's handle CORS OPTION query\n        Response r;\n        if (cors != null && Method.OPTIONS.equals(session.getMethod())) {\n            r = Response.newFixedLengthResponse(Status.OK, MIME_PLAINTEXT, null, 0);\n        } else {\n            r = defaultRespond(headers, session, uri);\n        }\n\n        if (cors != null) {\n            r = addCORSHeaders(headers, r, cors);\n        }\n        return r;\n    }\n\n    private Response defaultRespond(Map<String, String> headers, IHTTPSession session, String uri) {\n        // Remove URL arguments\n        uri = uri.trim().replace(File.separatorChar, '/');\n        if (uri.indexOf('?') >= 0) {\n            uri = uri.substring(0, uri.indexOf('?'));\n        }\n\n        // Prohibit getting out of current directory\n        if (uri.contains(\"../\")) {\n            return getForbiddenResponse(\"Won't serve ../ for security reasons.\");\n        }\n\n        boolean canServeUri = false;\n        File homeDir = null;\n        for (int i = 0; !canServeUri && i < this.rootDirs.size(); i++) {\n            homeDir = this.rootDirs.get(i);\n            canServeUri = canServeUri(uri, homeDir);\n        }\n        if (!canServeUri) {\n            return getNotFoundResponse();\n        }\n\n        // Browsers get confused without '/' after the directory, send a\n        // redirect.\n        File f = new File(homeDir, uri);\n        if (f.isDirectory() && !uri.endsWith(\"/\")) {\n            uri += \"/\";\n            Response res = newFixedLengthResponse(Status.REDIRECT, NanoHTTPD.MIME_HTML, \"<html><body>Redirected: <a href=\\\"\" + uri + \"\\\">\" + uri + \"</a></body></html>\");\n            res.addHeader(\"Location\", uri);\n            return res;\n        }\n\n        if (f.isDirectory()) {\n            // First look for index files (index.html, index.htm, etc) and if\n            // none found, list the directory if readable.\n            String indexFile = findIndexFileInDirectory(f);\n            if (indexFile == null) {\n                if (f.canRead()) {\n                    // No index file, list the directory if it is readable\n                    return newFixedLengthResponse(Status.OK, NanoHTTPD.MIME_HTML, listDirectory(uri, f));\n                } else {\n                    return getForbiddenResponse(\"No directory listing.\");\n                }\n            } else {\n                return respond(headers, session, uri + indexFile);\n            }\n        }\n        String mimeTypeForFile = getMimeTypeForFile(uri);\n        WebServerPlugin plugin = SimpleWebServer.mimeTypeHandlers.get(mimeTypeForFile);\n        Response response = null;\n        if (plugin != null && plugin.canServeUri(uri, homeDir)) {\n            response = plugin.serveFile(uri, headers, session, f, mimeTypeForFile);\n            if (response != null && response instanceof InternalRewrite) {\n                InternalRewrite rewrite = (InternalRewrite) response;\n                return respond(rewrite.getHeaders(), session, rewrite.getUri());\n            }\n        } else {\n            response = serveFile(uri, headers, f, mimeTypeForFile);\n        }\n        return response != null ? response : getNotFoundResponse();\n    }\n\n    @Override\n    public Response serve(IHTTPSession session) {\n        Map<String, String> header = session.getHeaders();\n        Map<String, String> parms = session.getParms();\n        String uri = session.getUri();\n\n        if (!this.quiet) {\n            System.out.println(session.getMethod() + \" '\" + uri + \"' \");\n\n            Iterator<String> e = header.keySet().iterator();\n            while (e.hasNext()) {\n                String value = e.next();\n                System.out.println(\"  HDR: '\" + value + \"' = '\" + header.get(value) + \"'\");\n            }\n            e = parms.keySet().iterator();\n            while (e.hasNext()) {\n                String value = e.next();\n                System.out.println(\"  PRM: '\" + value + \"' = '\" + parms.get(value) + \"'\");\n            }\n        }\n\n        for (File homeDir : this.rootDirs) {\n            // Make sure we won't die of an exception later\n            if (!homeDir.isDirectory()) {\n                return getInternalErrorResponse(\"given path is not a directory (\" + homeDir + \").\");\n            }\n        }\n        return respond(Collections.unmodifiableMap(header), session, uri);\n    }\n\n    /**\n     * Serves file from homeDir and its' subdirectories (only). Uses only URI,\n     * ignores all headers and HTTP parameters.\n     */\n    Response serveFile(String uri, Map<String, String> header, File file, String mime) {\n        Response res;\n        try {\n            // Calculate etag\n            String etag = Integer.toHexString((file.getAbsolutePath() + file.lastModified() + \"\" + file.length()).hashCode());\n\n            // Support (simple) skipping:\n            long startFrom = 0;\n            long endAt = -1;\n            String range = header.get(\"range\");\n            if (range != null) {\n                if (range.startsWith(\"bytes=\")) {\n                    range = range.substring(\"bytes=\".length());\n                    int minus = range.indexOf('-');\n                    try {\n                        if (minus > 0) {\n                            startFrom = Long.parseLong(range.substring(0, minus));\n                            endAt = Long.parseLong(range.substring(minus + 1));\n                        }\n                    } catch (NumberFormatException ignored) {\n                    }\n                }\n            }\n\n            // get if-range header. If present, it must match etag or else we\n            // should ignore the range request\n            String ifRange = header.get(\"if-range\");\n            boolean headerIfRangeMissingOrMatching = (ifRange == null || etag.equals(ifRange));\n\n            String ifNoneMatch = header.get(\"if-none-match\");\n            boolean headerIfNoneMatchPresentAndMatching = ifNoneMatch != null && (\"*\".equals(ifNoneMatch) || ifNoneMatch.equals(etag));\n\n            // Change return code and add Content-Range header when skipping is\n            // requested\n            long fileLen = file.length();\n\n            if (headerIfRangeMissingOrMatching && range != null && startFrom >= 0 && startFrom < fileLen) {\n                // range request that matches current etag\n                // and the startFrom of the range is satisfiable\n                if (headerIfNoneMatchPresentAndMatching) {\n                    // range request that matches current etag\n                    // and the startFrom of the range is satisfiable\n                    // would return range from file\n                    // respond with not-modified\n                    res = newFixedLengthResponse(Status.NOT_MODIFIED, mime, \"\");\n                    res.addHeader(\"ETag\", etag);\n                } else {\n                    if (endAt < 0) {\n                        endAt = fileLen - 1;\n                    }\n                    long newLen = endAt - startFrom + 1;\n                    if (newLen < 0) {\n                        newLen = 0;\n                    }\n\n                    FileInputStream fis = new FileInputStream(file);\n                    fis.skip(startFrom);\n\n                    res = Response.newFixedLengthResponse(Status.PARTIAL_CONTENT, mime, fis, newLen);\n                    res.addHeader(\"Accept-Ranges\", \"bytes\");\n                    res.addHeader(\"Content-Length\", \"\" + newLen);\n                    res.addHeader(\"Content-Range\", \"bytes \" + startFrom + \"-\" + endAt + \"/\" + fileLen);\n                    res.addHeader(\"ETag\", etag);\n                }\n            } else {\n\n                if (headerIfRangeMissingOrMatching && range != null && startFrom >= fileLen) {\n                    // return the size of the file\n                    // 4xx responses are not trumped by if-none-match\n                    res = newFixedLengthResponse(Status.RANGE_NOT_SATISFIABLE, NanoHTTPD.MIME_PLAINTEXT, \"\");\n                    res.addHeader(\"Content-Range\", \"bytes */\" + fileLen);\n                    res.addHeader(\"ETag\", etag);\n                } else if (range == null && headerIfNoneMatchPresentAndMatching) {\n                    // full-file-fetch request\n                    // would return entire file\n                    // respond with not-modified\n                    res = newFixedLengthResponse(Status.NOT_MODIFIED, mime, \"\");\n                    res.addHeader(\"ETag\", etag);\n                } else if (!headerIfRangeMissingOrMatching && headerIfNoneMatchPresentAndMatching) {\n                    // range request that doesn't match current etag\n                    // would return entire (different) file\n                    // respond with not-modified\n\n                    res = newFixedLengthResponse(Status.NOT_MODIFIED, mime, \"\");\n                    res.addHeader(\"ETag\", etag);\n                } else {\n                    // supply the file\n                    res = newFixedFileResponse(file, mime);\n                    res.addHeader(\"Content-Length\", \"\" + fileLen);\n                    res.addHeader(\"ETag\", etag);\n                }\n            }\n        } catch (IOException ioe) {\n            res = getForbiddenResponse(\"Reading file failed.\");\n        }\n\n        return res;\n    }\n\n    private Response newFixedFileResponse(File file, String mime) throws FileNotFoundException {\n        Response res;\n        res = Response.newFixedLengthResponse(Status.OK, mime, new FileInputStream(file), (int) file.length());\n        res.addHeader(\"Accept-Ranges\", \"bytes\");\n        return res;\n    }\n\n    protected Response addCORSHeaders(Map<String, String> queryHeaders, Response resp, String cors) {\n        resp.addHeader(\"Access-Control-Allow-Origin\", cors);\n        resp.addHeader(\"Access-Control-Allow-Headers\", calculateAllowHeaders(queryHeaders));\n        resp.addHeader(\"Access-Control-Allow-Credentials\", \"true\");\n        resp.addHeader(\"Access-Control-Allow-Methods\", ALLOWED_METHODS);\n        resp.addHeader(\"Access-Control-Max-Age\", \"\" + MAX_AGE);\n\n        return resp;\n    }\n\n    private String calculateAllowHeaders(Map<String, String> queryHeaders) {\n        // here we should use the given asked headers\n        // but NanoHttpd uses a Map whereas it is possible for requester to send\n        // several time the same header\n        // let's just use default values for this version\n        return System.getProperty(ACCESS_CONTROL_ALLOW_HEADER_PROPERTY_NAME, DEFAULT_ALLOWED_HEADERS);\n    }\n\n    private final static String ALLOWED_METHODS = \"GET, POST, PUT, DELETE, OPTIONS, HEAD\";\n\n    private final static int MAX_AGE = 42 * 60 * 60;\n\n    // explicitly relax visibility to package for tests purposes\n    public final static String DEFAULT_ALLOWED_HEADERS = \"origin,accept,content-type\";\n\n    public final static String ACCESS_CONTROL_ALLOW_HEADER_PROPERTY_NAME = \"AccessControlAllowHeader\";\n}\n"
  },
  {
    "path": "webserver/src/main/java/org/nanohttpd/webserver/WebServerPlugin.java",
    "content": "package org.nanohttpd.webserver;\n\n/*\n * #%L\n * NanoHttpd-Webserver\n * %%\n * Copyright (C) 2012 - 2015 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport java.io.File;\nimport java.util.Map;\n\nimport org.nanohttpd.protocols.http.IHTTPSession;\nimport org.nanohttpd.protocols.http.response.Response;\n\n/**\n * @author Paul S. Hawke (paul.hawke@gmail.com) On: 9/14/13 at 8:09 AM\n */\npublic interface WebServerPlugin {\n\n    boolean canServeUri(String uri, File rootDir);\n\n    void initialize(Map<String, String> commandLineOptions);\n\n    Response serveFile(String uri, Map<String, String> headers, IHTTPSession session, File file, String mimeType);\n}\n"
  },
  {
    "path": "webserver/src/main/java/org/nanohttpd/webserver/WebServerPluginInfo.java",
    "content": "package org.nanohttpd.webserver;\n\n/*\n * #%L\n * NanoHttpd-Webserver\n * %%\n * Copyright (C) 2012 - 2015 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\n/**\n * @author Paul S. Hawke (paul.hawke@gmail.com) On: 9/14/13 at 8:09 AM\n */\npublic interface WebServerPluginInfo {\n\n    String[] getIndexFilesForMimeType(String mime);\n\n    String[] getMimeTypes();\n\n    WebServerPlugin getWebServerPlugin(String mimeType);\n}\n"
  },
  {
    "path": "webserver/src/site/site.xml",
    "content": "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n<project name=\"${project.name}\">\n\t<skin>\n\t\t<groupId>org.apache.maven.skins</groupId>\n\t\t<artifactId>maven-fluido-skin</artifactId>\n\t\t<version>1.3.0</version>\n\t</skin>\n\t<bannerLeft>\n\t\t<src>../images/nanohttpd_logo.png</src>\n\t</bannerLeft>\n\t<bannerRight>\n\t\t<src>../images/nanohttpd_logo_text.png</src>\n\t</bannerRight>\n\t<publishDate position=\"left\" format=\"yyyy-MM-dd\" />\n\t<version position=\"right\" />\n\t<poweredBy>\n\t\t<logo name=\"Maven\" href=\"http://maven.apache.org/\"\n\t\t\timg=\"http://maven.apache.org/images/logos/maven-feather.png\" />\n\t</poweredBy>\n\t<custom>\n\t\t<fluidoSkin>\n\t\t\t<topBarEnabled>false</topBarEnabled>\n\t\t\t<sideBarEnabled>true</sideBarEnabled>\n\t\t\t<gitHub>\n\t\t\t\t<projectId>Nanohttpd/nanohttpd</projectId>\n\t\t\t\t<ribbonOrientation>right</ribbonOrientation>\n\t\t\t\t<ribbonColor>black</ribbonColor>\n\t\t\t</gitHub>\n\t\t</fluidoSkin>\n\t</custom>\n\t<body>\n\t\t<breadcrumbs>\n\t\t\t<item name=\"${project.name}\" href=\"index.html\" />\n\t\t</breadcrumbs>\n\t\t<menu name=\"Documentation\">\n\t\t\t<item name=\"About\" href=\"index.html\" />\n\t\t</menu>\n\t\t<menu ref=\"modules\" />\n\t\t<menu ref=\"reports\" />\n\t</body>\n</project>"
  },
  {
    "path": "webserver/src/test/java/org/nanohttpd/junit/webserver/AbstractTestHttpServer.java",
    "content": "package org.nanohttpd.junit.webserver;\n\n/*\n * #%L\n * NanoHttpd-Webserver\n * %%\n * Copyright (C) 2012 - 2015 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\n\nimport org.apache.http.HttpEntity;\n\n/**\n * @author Matthieu Brouillard [matthieu@brouillard.fr]\n */\npublic class AbstractTestHttpServer {\n\n    protected byte[] readContents(HttpEntity entity) throws IOException {\n        InputStream instream = entity.getContent();\n        return readContents(instream);\n    }\n\n    protected byte[] readContents(InputStream instream) throws IOException {\n        byte[] bytes;\n        ByteArrayOutputStream out = new ByteArrayOutputStream();\n        try {\n            byte[] buffer = new byte[1024];\n            int count;\n            while ((count = instream.read(buffer)) >= 0) {\n                out.write(buffer, 0, count);\n            }\n            bytes = out.toByteArray();\n        } finally {\n            instream.close();\n        }\n        return bytes;\n    }\n\n}\n"
  },
  {
    "path": "webserver/src/test/java/org/nanohttpd/junit/webserver/DummyPlugin.java",
    "content": "package org.nanohttpd.junit.webserver;\n\n/*\n * #%L\n * NanoHttpd-Webserver\n * %%\n * Copyright (C) 2012 - 2015 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport java.io.ByteArrayInputStream;\nimport java.io.File;\nimport java.io.InputStream;\nimport java.util.Map;\n\nimport org.nanohttpd.protocols.http.IHTTPSession;\nimport org.nanohttpd.protocols.http.response.Response;\nimport org.nanohttpd.protocols.http.response.Status;\nimport org.nanohttpd.webserver.InternalRewrite;\nimport org.nanohttpd.webserver.WebServerPlugin;\n\npublic class DummyPlugin implements WebServerPlugin {\n\n    @Override\n    public boolean canServeUri(String uri, File rootDir) {\n        return true;\n    }\n\n    @Override\n    public void initialize(Map<String, String> commandLineOptions) {\n    }\n\n    @Override\n    public Response serveFile(String uri, Map<String, String> headers, IHTTPSession session, File file, String mimeType) {\n        if (uri.contains(\"rewrite\")) {\n            return new InternalRewrite(headers, \"/testdir/test.html\");\n        }\n        byte[] bytes = \"<xml/>\".getBytes();\n        InputStream data = new ByteArrayInputStream(bytes);\n        return Response.newFixedLengthResponse(Status.OK, \"text/xml\", data, bytes.length);\n    }\n\n}\n"
  },
  {
    "path": "webserver/src/test/java/org/nanohttpd/junit/webserver/DummyPluginInfo.java",
    "content": "package org.nanohttpd.junit.webserver;\n\nimport org.nanohttpd.webserver.WebServerPlugin;\nimport org.nanohttpd.webserver.WebServerPluginInfo;\n\n/*\n * #%L\n * NanoHttpd-Webserver\n * %%\n * Copyright (C) 2012 - 2015 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\npublic class DummyPluginInfo implements WebServerPluginInfo {\n\n    @Override\n    public String[] getIndexFilesForMimeType(String mime) {\n\n        return new String[]{\n            \"index.xml\"\n        };\n    }\n\n    @Override\n    public String[] getMimeTypes() {\n        return new String[]{\n            \"text/xml\"\n        };\n    }\n\n    @Override\n    public WebServerPlugin getWebServerPlugin(String mimeType) {\n        return new DummyPlugin();\n    }\n\n}\n"
  },
  {
    "path": "webserver/src/test/java/org/nanohttpd/junit/webserver/TestCorsHttpServer.java",
    "content": "package org.nanohttpd.junit.webserver;\n\n/*\n * #%L\n * NanoHttpd-Webserver\n * %%\n * Copyright (C) 2012 - 2016 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport java.io.PipedInputStream;\nimport java.io.PipedOutputStream;\n\nimport org.apache.http.HttpEntity;\nimport org.apache.http.client.methods.CloseableHttpResponse;\nimport org.apache.http.client.methods.HttpGet;\nimport org.apache.http.client.methods.HttpOptions;\nimport org.apache.http.impl.client.CloseableHttpClient;\nimport org.apache.http.impl.client.HttpClients;\nimport org.junit.AfterClass;\nimport org.junit.Assert;\nimport org.junit.BeforeClass;\nimport org.junit.Test;\nimport org.nanohttpd.webserver.SimpleWebServer;\n\n/**\n * @author Matthieu Brouillard [matthieu@brouillard.fr]\n */\npublic class TestCorsHttpServer extends AbstractTestHttpServer {\n\n    private static PipedOutputStream stdIn;\n\n    private static Thread serverStartThread;\n\n    @BeforeClass\n    public static void setUp() throws Exception {\n        stdIn = new PipedOutputStream();\n        System.setIn(new PipedInputStream(stdIn));\n        serverStartThread = new Thread(new Runnable() {\n\n            @Override\n            public void run() {\n                String[] args = {\n                    \"--host\",\n                    \"localhost\",\n                    \"--port\",\n                    \"9090\",\n                    \"--dir\",\n                    \"src/test/resources\",\n                    \"--cors\"\n                };\n                SimpleWebServer.main(args);\n            }\n        });\n        serverStartThread.start();\n        // give the server some tine to start.\n        Thread.sleep(100);\n    }\n\n    @AfterClass\n    public static void tearDown() throws Exception {\n        stdIn.write(\"\\n\\n\".getBytes());\n        serverStartThread.join(2000);\n        Assert.assertFalse(serverStartThread.isAlive());\n    }\n\n    @Test\n    public void doTestOption() throws Exception {\n        CloseableHttpClient httpclient = HttpClients.createDefault();\n        HttpOptions httpOption = new HttpOptions(\"http://localhost:9090/xxx/yyy.html\");\n        CloseableHttpResponse response = httpclient.execute(httpOption);\n        Assert.assertEquals(200, response.getStatusLine().getStatusCode());\n        Assert.assertNotNull(\"Cors should have added a header: Access-Control-Allow-Origin\", response.getLastHeader(\"Access-Control-Allow-Origin\"));\n        Assert.assertEquals(\"Cors should have added a header: Access-Control-Allow-Origin: *\", \"*\", response.getLastHeader(\"Access-Control-Allow-Origin\").getValue());\n        response.close();\n    }\n\n    @Test\n    public void doSomeBasicTest() throws Exception {\n        CloseableHttpClient httpclient = HttpClients.createDefault();\n        HttpGet httpget = new HttpGet(\"http://localhost:9090/testdir/test.html\");\n        CloseableHttpResponse response = httpclient.execute(httpget);\n        HttpEntity entity = response.getEntity();\n        String string = new String(readContents(entity), \"UTF-8\");\n\n        Assert.assertNotNull(\"Cors should have added a header: Access-Control-Allow-Origin\", response.getLastHeader(\"Access-Control-Allow-Origin\"));\n        Assert.assertEquals(\"Cors should have added a header: Access-Control-Allow-Origin: *\", \"*\", response.getLastHeader(\"Access-Control-Allow-Origin\").getValue());\n        Assert.assertEquals(\"<html>\\n<head>\\n<title>dummy</title>\\n</head>\\n<body>\\n\\t<h1>it works</h1>\\n</body>\\n</html>\", string);\n        response.close();\n    }\n\n    @Test\n    public void testAccessControlAllowHeaderUsesDefaultsWithoutSystemProperty() throws Exception {\n        Assert.assertNull(\"no System \" + SimpleWebServer.ACCESS_CONTROL_ALLOW_HEADER_PROPERTY_NAME + \" shoudl be set\",\n                System.getProperty(SimpleWebServer.ACCESS_CONTROL_ALLOW_HEADER_PROPERTY_NAME));\n\n        CloseableHttpClient httpclient = HttpClients.createDefault();\n        HttpOptions httpOption = new HttpOptions(\"http://localhost:9090/xxx/yyy.html\");\n        CloseableHttpResponse response = httpclient.execute(httpOption);\n        Assert.assertEquals(200, response.getStatusLine().getStatusCode());\n        Assert.assertEquals(\"Cors should have added a header: Access-Control-Allow-Headers: \" + SimpleWebServer.DEFAULT_ALLOWED_HEADERS,\n                SimpleWebServer.DEFAULT_ALLOWED_HEADERS, response.getLastHeader(\"Access-Control-Allow-Headers\").getValue());\n        response.close();\n    }\n\n    @Test\n    public void testAccessControlAllowHeaderUsesSystemPropertyWhenSet() throws Exception {\n        Assert.assertNull(\"no System \" + SimpleWebServer.ACCESS_CONTROL_ALLOW_HEADER_PROPERTY_NAME + \" shoudl be set\",\n                System.getProperty(SimpleWebServer.ACCESS_CONTROL_ALLOW_HEADER_PROPERTY_NAME));\n\n        final String expectedValue = \"origin\";\n        System.setProperty(SimpleWebServer.ACCESS_CONTROL_ALLOW_HEADER_PROPERTY_NAME, expectedValue);\n\n        try {\n            CloseableHttpClient httpclient = HttpClients.createDefault();\n            HttpOptions httpOption = new HttpOptions(\"http://localhost:9090/xxx/yyy.html\");\n            CloseableHttpResponse response = httpclient.execute(httpOption);\n            Assert.assertEquals(200, response.getStatusLine().getStatusCode());\n            Assert.assertEquals(\"Cors should have added a header: Access-Control-Allow-Headers: \" + expectedValue, expectedValue,\n                    response.getLastHeader(\"Access-Control-Allow-Headers\").getValue());\n            response.close();\n        } finally {\n            System.clearProperty(SimpleWebServer.ACCESS_CONTROL_ALLOW_HEADER_PROPERTY_NAME);\n        }\n    }\n}\n"
  },
  {
    "path": "webserver/src/test/java/org/nanohttpd/junit/webserver/TestCorsHttpServerWithSingleOrigin.java",
    "content": "package org.nanohttpd.junit.webserver;\n\n/*\n * #%L\n * NanoHttpd-Webserver\n * %%\n * Copyright (C) 2012 - 2016 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport java.io.PipedInputStream;\nimport java.io.PipedOutputStream;\n\nimport org.apache.http.HttpEntity;\nimport org.apache.http.client.methods.CloseableHttpResponse;\nimport org.apache.http.client.methods.HttpGet;\nimport org.apache.http.client.methods.HttpOptions;\nimport org.apache.http.impl.client.CloseableHttpClient;\nimport org.apache.http.impl.client.HttpClients;\nimport org.junit.AfterClass;\nimport org.junit.Assert;\nimport org.junit.BeforeClass;\nimport org.junit.Test;\nimport org.nanohttpd.webserver.SimpleWebServer;\n\n/**\n * @author Matthieu Brouillard [matthieu@brouillard.fr]\n */\npublic class TestCorsHttpServerWithSingleOrigin extends AbstractTestHttpServer {\n\n    private static PipedOutputStream stdIn;\n\n    private static Thread serverStartThread;\n\n    @BeforeClass\n    public static void setUp() throws Exception {\n        stdIn = new PipedOutputStream();\n        System.setIn(new PipedInputStream(stdIn));\n        serverStartThread = new Thread(new Runnable() {\n\n            @Override\n            public void run() {\n                String[] args = {\n                    \"--host\",\n                    \"localhost\",\n                    \"--port\",\n                    \"9090\",\n                    \"--dir\",\n                    \"src/test/resources\",\n                    \"--cors=http://localhost:9090\"\n                };\n                SimpleWebServer.main(args);\n            }\n        });\n        serverStartThread.start();\n        // give the server some tine to start.\n        Thread.sleep(100);\n    }\n\n    @AfterClass\n    public static void tearDown() throws Exception {\n        stdIn.write(\"\\n\\n\".getBytes());\n        serverStartThread.join(2000);\n        Assert.assertFalse(serverStartThread.isAlive());\n    }\n\n    @Test\n    public void doTestOption() throws Exception {\n        CloseableHttpClient httpclient = HttpClients.createDefault();\n        HttpOptions httpOption = new HttpOptions(\"http://localhost:9090/xxx/yyy.html\");\n        CloseableHttpResponse response = httpclient.execute(httpOption);\n        Assert.assertEquals(200, response.getStatusLine().getStatusCode());\n        Assert.assertNotNull(\"Cors should have added a header: Access-Control-Allow-Origin\", response.getLastHeader(\"Access-Control-Allow-Origin\"));\n        Assert.assertEquals(\"Cors should have added a header: Access-Control-Allow-Origin: http://localhost:9090\", \"http://localhost:9090\",\n                response.getLastHeader(\"Access-Control-Allow-Origin\").getValue());\n        response.close();\n    }\n\n    @Test\n    public void doSomeBasicTest() throws Exception {\n        CloseableHttpClient httpclient = HttpClients.createDefault();\n        HttpGet httpget = new HttpGet(\"http://localhost:9090/testdir/test.html\");\n        CloseableHttpResponse response = httpclient.execute(httpget);\n        HttpEntity entity = response.getEntity();\n        String string = new String(readContents(entity), \"UTF-8\");\n\n        Assert.assertNotNull(\"Cors should have added a header: Access-Control-Allow-Origin\", response.getLastHeader(\"Access-Control-Allow-Origin\"));\n        Assert.assertEquals(\"Cors should have added a header: Access-Control-Allow-Origin: http://localhost:9090\", \"http://localhost:9090\",\n                response.getLastHeader(\"Access-Control-Allow-Origin\").getValue());\n        Assert.assertEquals(\"<html>\\n<head>\\n<title>dummy</title>\\n</head>\\n<body>\\n\\t<h1>it works</h1>\\n</body>\\n</html>\", string);\n        response.close();\n    }\n}\n"
  },
  {
    "path": "webserver/src/test/java/org/nanohttpd/junit/webserver/TestHttpServer.java",
    "content": "package org.nanohttpd.junit.webserver;\n\n/*\n * #%L\n * NanoHttpd-Webserver\n * %%\n * Copyright (C) 2012 - 2015 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\nimport static org.hamcrest.CoreMatchers.allOf;\nimport static org.hamcrest.CoreMatchers.containsString;\nimport static org.hamcrest.CoreMatchers.not;\n\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.PipedInputStream;\nimport java.io.PipedOutputStream;\nimport java.io.UnsupportedEncodingException;\n\nimport org.apache.http.HttpEntity;\nimport org.apache.http.client.ClientProtocolException;\nimport org.apache.http.client.methods.CloseableHttpResponse;\nimport org.apache.http.client.methods.HttpGet;\nimport org.apache.http.impl.client.CloseableHttpClient;\nimport org.apache.http.impl.client.HttpClients;\nimport org.junit.AfterClass;\nimport org.junit.Assert;\nimport org.junit.BeforeClass;\nimport org.junit.Test;\nimport org.nanohttpd.webserver.SimpleWebServer;\n\npublic class TestHttpServer extends AbstractTestHttpServer {\n\n    private static PipedOutputStream stdIn;\n\n    private static Thread serverStartThread;\n\n    @BeforeClass\n    public static void setUp() throws Exception {\n        stdIn = new PipedOutputStream();\n        System.setIn(new PipedInputStream(stdIn));\n        serverStartThread = new Thread(new Runnable() {\n\n            @Override\n            public void run() {\n                String[] args = {\n                    \"--host\",\n                    \"localhost\",\n                    \"--port\",\n                    \"9090\",\n                    \"--dir\",\n                    \"src/test/resources\"\n                };\n                SimpleWebServer.main(args);\n            }\n        });\n        serverStartThread.start();\n        // give the server some tine to start.\n        Thread.sleep(100);\n    }\n\n    @AfterClass\n    public static void tearDown() throws Exception {\n        stdIn.write(\"\\n\\n\".getBytes());\n        serverStartThread.join(2000);\n        Assert.assertFalse(serverStartThread.isAlive());\n    }\n\n    @Test\n    public void doTest404() throws Exception {\n        CloseableHttpClient httpclient = HttpClients.createDefault();\n        HttpGet httpget = new HttpGet(\"http://localhost:9090/xxx/yyy.html\");\n        CloseableHttpResponse response = httpclient.execute(httpget);\n        Assert.assertEquals(404, response.getStatusLine().getStatusCode());\n        response.close();\n    }\n\n    @Test\n    public void doPlugin() throws Exception {\n        CloseableHttpClient httpclient = HttpClients.createDefault();\n        HttpGet httpget = new HttpGet(\"http://localhost:9090/index.xml\");\n        CloseableHttpResponse response = httpclient.execute(httpget);\n        String string = new String(readContents(response.getEntity()), \"UTF-8\");\n        Assert.assertEquals(\"<xml/>\", string);\n        response.close();\n\n        httpget = new HttpGet(\"http://localhost:9090/testdir/testdir/different.xml\");\n        response = httpclient.execute(httpget);\n        string = new String(readContents(response.getEntity()), \"UTF-8\");\n        Assert.assertEquals(\"<xml/>\", string);\n        response.close();\n    }\n\n    @Test\n    public void doSomeBasicTest() throws Exception {\n        CloseableHttpClient httpclient = HttpClients.createDefault();\n        HttpGet httpget = new HttpGet(\"http://localhost:9090/testdir/test.html\");\n        CloseableHttpResponse response = httpclient.execute(httpget);\n        HttpEntity entity = response.getEntity();\n        String string = new String(readContents(entity), \"UTF-8\");\n        Assert.assertEquals(\"<html>\\n<head>\\n<title>dummy</title>\\n</head>\\n<body>\\n\\t<h1>it works</h1>\\n</body>\\n</html>\", string);\n        response.close();\n\n        httpget = new HttpGet(\"http://localhost:9090/\");\n        response = httpclient.execute(httpget);\n        entity = response.getEntity();\n        string = new String(readContents(entity), \"UTF-8\");\n        Assert.assertTrue(string.indexOf(\"testdir\") > 0);\n        response.close();\n\n        httpget = new HttpGet(\"http://localhost:9090/testdir\");\n        response = httpclient.execute(httpget);\n        entity = response.getEntity();\n        string = new String(readContents(entity), \"UTF-8\");\n        Assert.assertTrue(string.indexOf(\"test.html\") > 0);\n        response.close();\n\n        httpget = new HttpGet(\"http://localhost:9090/testdir/testpdf.pdf\");\n        response = httpclient.execute(httpget);\n        entity = response.getEntity();\n\n        byte[] actual = readContents(entity);\n        byte[] expected = readContents(new FileInputStream(\"src/test/resources/testdir/testpdf.pdf\"));\n        Assert.assertArrayEquals(expected, actual);\n        response.close();\n\n    }\n\n    @Test\n    public void doArgumentTest() throws InterruptedException, UnsupportedEncodingException, IOException {\n        final String testPort = \"9458\";\n        Thread testServer = new Thread(new Runnable() {\n\n            @Override\n            public void run() {\n                String[] args = {\n                    \"-h\",\n                    \"localhost\",\n                    \"-p\",\n                    testPort,\n                    \"-d\",\n                    \"src/test/resources\"\n                };\n                SimpleWebServer.main(args);\n            }\n        });\n\n        testServer.start();\n        Thread.sleep(200);\n\n        HttpGet httpget = new HttpGet(\"http://localhost:\" + testPort + \"/\");\n        CloseableHttpClient httpclient = HttpClients.createDefault();\n\n        CloseableHttpResponse response = null;\n        try {\n            response = httpclient.execute(httpget);\n            HttpEntity entity = response.getEntity();\n            String str = new String(readContents(entity), \"UTF-8\");\n            Assert.assertTrue(\"The response entity didn't contain the string 'testdir'\", str.indexOf(\"testdir\") >= 0);\n        } finally {\n            if (response != null)\n                response.close();\n        }\n    }\n\n    @Test\n    public void testURLContainsParentDirectory() throws ClientProtocolException, IOException {\n        CloseableHttpResponse response = null;\n        try {\n            CloseableHttpClient httpClient = HttpClients.createDefault();\n            HttpGet httpGet = new HttpGet(\"http://localhost:9090/../test.html\");\n            response = httpClient.execute(httpGet);\n            Assert.assertEquals(\"The response status should be 403(Forbidden), \" + \"since the server won't serve requests with '../' due to security reasons\", 403, response\n                    .getStatusLine().getStatusCode());\n        } finally {\n            if (response != null) {\n                response.close();\n            }\n        }\n    }\n\n    @Test\n    public void testIndexFileIsShownWhenURLEndsWithDirectory() throws ClientProtocolException, IOException {\n        CloseableHttpResponse response = null;\n        try {\n            CloseableHttpClient httpClient = HttpClients.createDefault();\n            HttpGet httpGet = new HttpGet(\"http://localhost:9090/testdir/testdir\");\n            response = httpClient.execute(httpGet);\n            HttpEntity entity = response.getEntity();\n            String responseString = new String(readContents(entity), \"UTF-8\");\n            Assert.assertThat(\"When the URL ends with a directory, and if an index.html file is present in that directory,\" + \" the server should respond with that file\",\n                    responseString, containsString(\"Simple index file\"));\n        } finally {\n            if (response != null) {\n                response.close();\n            }\n        }\n    }\n\n    @Test\n    public void testPluginInternalRewrite() throws ClientProtocolException, IOException {\n        CloseableHttpResponse response = null;\n        try {\n            CloseableHttpClient httpClient = HttpClients.createDefault();\n            HttpGet httpGet = new HttpGet(\"http://localhost:9090/rewrite/index.xml\");\n            response = httpClient.execute(httpGet);\n            HttpEntity entity = response.getEntity();\n            String responseString = new String(readContents(entity), \"UTF-8\");\n            Assert.assertThat(\"If a plugin returns an InternalRewrite from the serveFile method, the rewritten request should be served\", responseString,\n                    allOf(containsString(\"dummy\"), containsString(\"it works\")));\n        } finally {\n            if (response != null) {\n                response.close();\n            }\n        }\n    }\n\n    @Test\n    public void testRangeHeaderWithStartPositionOnly() throws ClientProtocolException, IOException {\n        CloseableHttpResponse response = null;\n        try {\n            HttpGet httpGet = new HttpGet(\"http://localhost:9090/testdir/test.html\");\n            httpGet.addHeader(\"range\", \"bytes=10-\");\n            CloseableHttpClient httpClient = HttpClients.createDefault();\n            response = httpClient.execute(httpGet);\n            HttpEntity entity = response.getEntity();\n            String responseString = new String(readContents(entity), \"UTF-8\");\n            Assert.assertThat(\"The data from the beginning of the file should have been skipped as specified in the 'range' header\", responseString,\n                    not(containsString(\"<head>\")));\n            Assert.assertThat(\"The response should contain the data from the end of the file since end position was not given in the 'range' header\", responseString,\n                    containsString(\"</head>\"));\n            Assert.assertEquals(\"The content length should be the length starting from the requested byte\", \"74\", response.getHeaders(\"Content-Length\")[0].getValue());\n            Assert.assertEquals(\"The 'Content-Range' header should contain the correct lengths and offsets based on the range served\", \"bytes 10-83/84\",\n                    response.getHeaders(\"Content-Range\")[0].getValue());\n            Assert.assertEquals(\"Response status for a successful range request should be PARTIAL_CONTENT(206)\", 206, response.getStatusLine().getStatusCode());\n        } finally {\n            if (response != null) {\n                response.close();\n            }\n        }\n    }\n\n    @Test\n    public void testRangeStartGreaterThanFileLength() throws ClientProtocolException, IOException {\n        CloseableHttpResponse response = null;\n        try {\n            HttpGet httpGet = new HttpGet(\"http://localhost:9090/testdir/test.html\");\n            httpGet.addHeader(\"range\", \"bytes=1000-\");\n            CloseableHttpClient httpClient = HttpClients.createDefault();\n            response = httpClient.execute(httpGet);\n            Assert.assertEquals(\"Response status for a request with 'range' header value which exceeds file length should be RANGE_NOT_SATISFIABLE(416)\", 416, response\n                    .getStatusLine().getStatusCode());\n            Assert.assertEquals(\"The 'Content-Range' header should contain the correct lengths and offsets based on the range served\", \"bytes */84\",\n                    response.getHeaders(\"Content-Range\")[0].getValue());\n        } finally {\n            if (response != null) {\n                response.close();\n            }\n        }\n    }\n\n    @Test\n    public void testRangeHeaderWithStartAndEndPosition() throws ClientProtocolException, IOException {\n        CloseableHttpResponse response = null;\n        try {\n            HttpGet httpGet = new HttpGet(\"http://localhost:9090/testdir/test.html\");\n            httpGet.addHeader(\"range\", \"bytes=10-40\");\n            CloseableHttpClient httpClient = HttpClients.createDefault();\n            response = httpClient.execute(httpGet);\n            HttpEntity entity = response.getEntity();\n            String responseString = new String(readContents(entity), \"UTF-8\");\n            Assert.assertThat(\"The data from the beginning of the file should have been skipped as specified in the 'range' header\", responseString,\n                    not(containsString(\"<head>\")));\n            Assert.assertThat(\"The data from the end of the file should have been skipped as specified in the 'range' header\", responseString, not(containsString(\"</head>\")));\n            Assert.assertEquals(\"The 'Content-Length' should be the length from the requested start position to end position\", \"31\",\n                    response.getHeaders(\"Content-Length\")[0].getValue());\n            Assert.assertEquals(\"The 'Contnet-Range' header should contain the correct lengths and offsets based on the range served\", \"bytes 10-40/84\",\n                    response.getHeaders(\"Content-Range\")[0].getValue());\n            Assert.assertEquals(\"Response status for a successful request with 'range' header should be PARTIAL_CONTENT(206)\", 206, response.getStatusLine().getStatusCode());\n        } finally {\n            if (response != null) {\n                response.close();\n            }\n        }\n    }\n\n    @Test\n    public void testIfNoneMatchHeader() throws ClientProtocolException, IOException {\n        CloseableHttpResponse response = null;\n        try {\n            HttpGet httpGet = new HttpGet(\"http://localhost:9090/testdir/test.html\");\n            httpGet.addHeader(\"if-none-match\", \"*\");\n            CloseableHttpClient httpClient = HttpClients.createDefault();\n            response = httpClient.execute(httpGet);\n            Assert.assertEquals(\"The response status to a reqeuest with 'if-non-match=*' header should be NOT_MODIFIED(304), if the file exists\", 304, response\n                    .getStatusLine().getStatusCode());\n        } finally {\n            if (response != null) {\n                response.close();\n            }\n        }\n    }\n\n    @Test\n    public void testRangeHeaderAndIfNoneMatchHeader() throws ClientProtocolException, IOException {\n        CloseableHttpResponse response = null;\n        try {\n            HttpGet httpGet = new HttpGet(\"http://localhost:9090/testdir/test.html\");\n            httpGet.addHeader(\"range\", \"bytes=10-20\");\n            httpGet.addHeader(\"if-none-match\", \"*\");\n            CloseableHttpClient httpClient = HttpClients.createDefault();\n            response = httpClient.execute(httpGet);\n            Assert.assertEquals(\"The response status to a reqeuest with 'if-non-match=*' header and 'range' header should be NOT_MODIFIED(304),\"\n                    + \" if the file exists, because 'if-non-match' header should be given priority\", 304, response.getStatusLine().getStatusCode());\n        } finally {\n            if (response != null) {\n                response.close();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "webserver/src/test/resources/META-INF/services/org.nanohttpd.webserver.WebServerPluginInfo",
    "content": "org.nanohttpd.junit.webserver.DummyPluginInfo"
  },
  {
    "path": "webserver/src/test/resources/testdir/test.html",
    "content": "<html>\n<head>\n<title>dummy</title>\n</head>\n<body>\n\t<h1>it works</h1>\n</body>\n</html>"
  },
  {
    "path": "webserver/src/test/resources/testdir/testdir/different.xml",
    "content": "<xml>\n\tThis sould not show up ;-)\n</xml>"
  },
  {
    "path": "webserver/src/test/resources/testdir/testdir/index.html",
    "content": "<html>\n<head>\n<title>Simple index file</title>\n</head>\n</html>"
  },
  {
    "path": "websocket/.gitignore",
    "content": "/.settings/\n/LICENSE.txt\n"
  },
  {
    "path": "websocket/build.gradle",
    "content": "description = 'NanoHttpd-Websocket'\n\ndependencies {\n\tcompile project(':nanohttpd')\n\ttestCompile group: 'org.mockito', name: 'mockito-all', version: '1.9.5'\n\ttestCompile group: 'org.eclipse.jetty.websocket', name: 'websocket-client', version: '9.3.0.M2'\n}\n\ntask wrapper(type: Wrapper) {\n\tgradleVersion = \"4.4.1\"\n}\n"
  },
  {
    "path": "websocket/pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n\t<modelVersion>4.0.0</modelVersion>\n\t<parent>\n\t\t<groupId>org.nanohttpd</groupId>\n\t\t<artifactId>nanohttpd-project</artifactId>\n\t\t<version>2.3.2-SNAPSHOT</version>\n\t</parent>\n\t<artifactId>nanohttpd-websocket</artifactId>\n\t<packaging>jar</packaging>\n\t<name>NanoHttpd-Websocket</name>\n\t<description>nanohttpd-websocket is a very low profile websocket server based on nanohttpd.</description>\n\t<build>\n\t\t<plugins>\n\t\t\t<plugin>\n\t\t\t\t<groupId>org.apache.maven.plugins</groupId>\n\t\t\t\t<artifactId>maven-jar-plugin</artifactId>\n\t\t\t\t<executions>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>default-jar</id>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<excludes>\n\t\t\t\t\t\t\t\t<exclude>**/samples/**</exclude>\n\t\t\t\t\t\t\t</excludes>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t\t<execution>\n\t\t\t\t\t\t<id>echo-jar</id>\n\t\t\t\t\t\t<phase>package</phase>\n\t\t\t\t\t\t<goals>\n\t\t\t\t\t\t\t<goal>jar</goal>\n\t\t\t\t\t\t</goals>\n\t\t\t\t\t\t<configuration>\n\t\t\t\t\t\t\t<classifier>echo</classifier>\n\t\t\t\t\t\t\t<archive>\n\t\t\t\t\t\t\t\t<manifest>\n\t\t\t\t\t\t\t\t\t<addClasspath>true</addClasspath>\n\t\t\t\t\t\t\t\t\t<mainClass>fi.iki.elonen.samples.echo.EchoSocketSample</mainClass>\n\t\t\t\t\t\t\t\t</manifest>\n\t\t\t\t\t\t\t</archive>\n\t\t\t\t\t\t</configuration>\n\t\t\t\t\t</execution>\n\t\t\t\t</executions>\n\t\t\t</plugin>\n\t\t</plugins>\n\t</build>\n\t<dependencies>\n\t\t<dependency>\n\t\t\t<groupId>${project.groupId}</groupId>\n\t\t\t<artifactId>nanohttpd</artifactId>\n\t\t\t<version>${project.version}</version>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.mockito</groupId>\n\t\t\t<artifactId>mockito-all</artifactId>\n\t\t\t<version>1.9.5</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t\t<dependency>\n\t\t\t<groupId>org.eclipse.jetty.websocket</groupId>\n\t\t\t<artifactId>websocket-client</artifactId>\n\t\t\t<version>9.3.0.M2</version>\n\t\t\t<scope>test</scope>\n\t\t</dependency>\n\t</dependencies>\n\t<properties>\n\t\t<minimal.coverage>0.67</minimal.coverage>\n\t</properties>\n</project>\n"
  },
  {
    "path": "websocket/src/main/java/org/nanohttpd/protocols/websockets/CloseCode.java",
    "content": "package org.nanohttpd.protocols.websockets;\n\n/*\n * #%L\n * NanoHttpd-Websocket\n * %%\n * Copyright (C) 2012 - 2016 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\npublic enum CloseCode {\n    NormalClosure(1000),\n    GoingAway(1001),\n    ProtocolError(1002),\n    UnsupportedData(1003),\n    NoStatusRcvd(1005),\n    AbnormalClosure(1006),\n    InvalidFramePayloadData(1007),\n    PolicyViolation(1008),\n    MessageTooBig(1009),\n    MandatoryExt(1010),\n    InternalServerError(1011),\n    TLSHandshake(1015);\n\n    public static CloseCode find(int value) {\n        for (CloseCode code : values()) {\n            if (code.getValue() == value) {\n                return code;\n            }\n        }\n        return null;\n    }\n\n    private final int code;\n\n    private CloseCode(int code) {\n        this.code = code;\n    }\n\n    public int getValue() {\n        return this.code;\n    }\n}\n"
  },
  {
    "path": "websocket/src/main/java/org/nanohttpd/protocols/websockets/CloseFrame.java",
    "content": "package org.nanohttpd.protocols.websockets;\n\n/*\n * #%L\n * NanoHttpd-Websocket\n * %%\n * Copyright (C) 2012 - 2016 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport java.nio.charset.CharacterCodingException;\n\npublic class CloseFrame extends WebSocketFrame {\n\n    private static byte[] generatePayload(CloseCode code, String closeReason) throws CharacterCodingException {\n        if (code != null) {\n            byte[] reasonBytes = text2Binary(closeReason);\n            byte[] payload = new byte[reasonBytes.length + 2];\n            payload[0] = (byte) (code.getValue() >> 8 & 0xFF);\n            payload[1] = (byte) (code.getValue() & 0xFF);\n            System.arraycopy(reasonBytes, 0, payload, 2, reasonBytes.length);\n            return payload;\n        } else {\n            return new byte[0];\n        }\n    }\n\n    private CloseCode _closeCode;\n\n    private String _closeReason;\n\n    public CloseFrame(CloseCode code, String closeReason) throws CharacterCodingException {\n        super(OpCode.Close, true, generatePayload(code, closeReason));\n    }\n\n    public CloseFrame(WebSocketFrame wrap) throws CharacterCodingException {\n        super(wrap);\n        assert wrap.getOpCode() == OpCode.Close;\n        if (wrap.getBinaryPayload().length >= 2) {\n            this._closeCode = CloseCode.find((wrap.getBinaryPayload()[0] & 0xFF) << 8 | wrap.getBinaryPayload()[1] & 0xFF);\n            this._closeReason = binary2Text(getBinaryPayload(), 2, getBinaryPayload().length - 2);\n        }\n    }\n\n    public CloseCode getCloseCode() {\n        return this._closeCode;\n    }\n\n    public String getCloseReason() {\n        return this._closeReason;\n    }\n}\n"
  },
  {
    "path": "websocket/src/main/java/org/nanohttpd/protocols/websockets/NanoWSD.java",
    "content": "package org.nanohttpd.protocols.websockets;\n\n/*\n * #%L\n * NanoHttpd-Websocket\n * %%\n * Copyright (C) 2012 - 2016 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport java.security.MessageDigest;\nimport java.security.NoSuchAlgorithmException;\nimport java.util.Map;\nimport java.util.logging.Logger;\n\nimport org.nanohttpd.protocols.http.IHTTPSession;\nimport org.nanohttpd.protocols.http.NanoHTTPD;\nimport org.nanohttpd.protocols.http.response.Response;\nimport org.nanohttpd.protocols.http.response.Status;\nimport org.nanohttpd.util.IHandler;\n\npublic abstract class NanoWSD extends NanoHTTPD {\n\n    /**\n     * logger to log to.\n     */\n    public static final Logger LOG = Logger.getLogger(NanoWSD.class.getName());\n\n    public static final String HEADER_UPGRADE = \"upgrade\";\n\n    public static final String HEADER_UPGRADE_VALUE = \"websocket\";\n\n    public static final String HEADER_CONNECTION = \"connection\";\n\n    public static final String HEADER_CONNECTION_VALUE = \"Upgrade\";\n\n    public static final String HEADER_WEBSOCKET_VERSION = \"sec-websocket-version\";\n\n    public static final String HEADER_WEBSOCKET_VERSION_VALUE = \"13\";\n\n    public static final String HEADER_WEBSOCKET_KEY = \"sec-websocket-key\";\n\n    public static final String HEADER_WEBSOCKET_ACCEPT = \"sec-websocket-accept\";\n\n    public static final String HEADER_WEBSOCKET_PROTOCOL = \"sec-websocket-protocol\";\n\n    private final static String WEBSOCKET_KEY_MAGIC = \"258EAFA5-E914-47DA-95CA-C5AB0DC85B11\";\n\n    private final static char[] ALPHABET = \"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\".toCharArray();\n\n    /**\n     * Translates the specified byte array into Base64 string.\n     * <p>\n     * Android has android.util.Base64, sun has sun.misc.Base64Encoder, Java 8\n     * hast java.util.Base64, I have this from stackoverflow:\n     * http://stackoverflow.com/a/4265472\n     * </p>\n     * \n     * @param buf\n     *            the byte array (not null)\n     * @return the translated Base64 string (not null)\n     */\n    private static String encodeBase64(byte[] buf) {\n        int size = buf.length;\n        char[] ar = new char[(size + 2) / 3 * 4];\n        int a = 0;\n        int i = 0;\n        while (i < size) {\n            byte b0 = buf[i++];\n            byte b1 = i < size ? buf[i++] : 0;\n            byte b2 = i < size ? buf[i++] : 0;\n\n            int mask = 0x3F;\n            ar[a++] = NanoWSD.ALPHABET[b0 >> 2 & mask];\n            ar[a++] = NanoWSD.ALPHABET[(b0 << 4 | (b1 & 0xFF) >> 4) & mask];\n            ar[a++] = NanoWSD.ALPHABET[(b1 << 2 | (b2 & 0xFF) >> 6) & mask];\n            ar[a++] = NanoWSD.ALPHABET[b2 & mask];\n        }\n        switch (size % 3) {\n            case 1:\n                ar[--a] = '=';\n            case 2:\n                ar[--a] = '=';\n        }\n        return new String(ar);\n    }\n\n    public static String makeAcceptKey(String key) throws NoSuchAlgorithmException {\n        MessageDigest md = MessageDigest.getInstance(\"SHA-1\");\n        String text = key + NanoWSD.WEBSOCKET_KEY_MAGIC;\n        md.update(text.getBytes(), 0, text.length());\n        byte[] sha1hash = md.digest();\n        return encodeBase64(sha1hash);\n    }\n\n    protected final class Interceptor implements IHandler<IHTTPSession, Response> {\n\n        public Interceptor() {\n        }\n\n        @Override\n        public Response handle(IHTTPSession input) {\n            return handleWebSocket(input);\n        }\n    }\n\n    public NanoWSD(int port) {\n        super(port);\n        addHTTPInterceptor(new Interceptor());\n    }\n\n    public NanoWSD(String hostname, int port) {\n        super(hostname, port);\n        addHTTPInterceptor(new Interceptor());\n    }\n\n    private boolean isWebSocketConnectionHeader(Map<String, String> headers) {\n        String connection = headers.get(NanoWSD.HEADER_CONNECTION);\n        return connection != null && connection.toLowerCase().contains(NanoWSD.HEADER_CONNECTION_VALUE.toLowerCase());\n    }\n\n    protected boolean isWebsocketRequested(IHTTPSession session) {\n        Map<String, String> headers = session.getHeaders();\n        String upgrade = headers.get(NanoWSD.HEADER_UPGRADE);\n        boolean isCorrectConnection = isWebSocketConnectionHeader(headers);\n        boolean isUpgrade = NanoWSD.HEADER_UPGRADE_VALUE.equalsIgnoreCase(upgrade);\n        return isUpgrade && isCorrectConnection;\n    }\n\n    // --------------------------------Listener--------------------------------\n\n    protected abstract WebSocket openWebSocket(IHTTPSession handshake);\n\n    public Response handleWebSocket(final IHTTPSession session) {\n        Map<String, String> headers = session.getHeaders();\n        if (isWebsocketRequested(session)) {\n            if (!NanoWSD.HEADER_WEBSOCKET_VERSION_VALUE.equalsIgnoreCase(headers.get(NanoWSD.HEADER_WEBSOCKET_VERSION))) {\n                return Response.newFixedLengthResponse(Status.BAD_REQUEST, NanoHTTPD.MIME_PLAINTEXT,\n                        \"Invalid Websocket-Version \" + headers.get(NanoWSD.HEADER_WEBSOCKET_VERSION));\n            }\n\n            if (!headers.containsKey(NanoWSD.HEADER_WEBSOCKET_KEY)) {\n                return Response.newFixedLengthResponse(Status.BAD_REQUEST, NanoHTTPD.MIME_PLAINTEXT, \"Missing Websocket-Key\");\n            }\n\n            WebSocket webSocket = openWebSocket(session);\n            Response handshakeResponse = webSocket.getHandshakeResponse();\n            try {\n                handshakeResponse.addHeader(NanoWSD.HEADER_WEBSOCKET_ACCEPT, makeAcceptKey(headers.get(NanoWSD.HEADER_WEBSOCKET_KEY)));\n            } catch (NoSuchAlgorithmException e) {\n                return Response.newFixedLengthResponse(Status.INTERNAL_ERROR, NanoHTTPD.MIME_PLAINTEXT,\n                        \"The SHA-1 Algorithm required for websockets is not available on the server.\");\n            }\n\n            if (headers.containsKey(NanoWSD.HEADER_WEBSOCKET_PROTOCOL)) {\n                handshakeResponse.addHeader(NanoWSD.HEADER_WEBSOCKET_PROTOCOL, headers.get(NanoWSD.HEADER_WEBSOCKET_PROTOCOL).split(\",\")[0]);\n            }\n\n            return handshakeResponse;\n        } else {\n            return null;\n        }\n    }\n}\n"
  },
  {
    "path": "websocket/src/main/java/org/nanohttpd/protocols/websockets/OpCode.java",
    "content": "package org.nanohttpd.protocols.websockets;\n\n/*\n * #%L\n * NanoHttpd-Websocket\n * %%\n * Copyright (C) 2012 - 2016 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\npublic enum OpCode {\n    Continuation(0),\n    Text(1),\n    Binary(2),\n    Close(8),\n    Ping(9),\n    Pong(10);\n\n    public static OpCode find(byte value) {\n        for (OpCode opcode : values()) {\n            if (opcode.getValue() == value) {\n                return opcode;\n            }\n        }\n        return null;\n    }\n\n    private final byte code;\n\n    private OpCode(int code) {\n        this.code = (byte) code;\n    }\n\n    public byte getValue() {\n        return this.code;\n    }\n\n    public boolean isControlFrame() {\n        return this == Close || this == Ping || this == Pong;\n    }\n}\n"
  },
  {
    "path": "websocket/src/main/java/org/nanohttpd/protocols/websockets/State.java",
    "content": "package org.nanohttpd.protocols.websockets;\n\n/*\n * #%L\n * NanoHttpd-Websocket\n * %%\n * Copyright (C) 2012 - 2016 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\npublic enum State {\n    UNCONNECTED,\n    CONNECTING,\n    OPEN,\n    CLOSING,\n    CLOSED\n}\n"
  },
  {
    "path": "websocket/src/main/java/org/nanohttpd/protocols/websockets/WebSocket.java",
    "content": "package org.nanohttpd.protocols.websockets;\n\n/*\n * #%L\n * NanoHttpd-Websocket\n * %%\n * Copyright (C) 2012 - 2016 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.nio.charset.CharacterCodingException;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.logging.Level;\n\nimport org.nanohttpd.protocols.http.IHTTPSession;\nimport org.nanohttpd.protocols.http.response.Response;\nimport org.nanohttpd.protocols.http.response.Status;\n\npublic abstract class WebSocket {\n\n    private final InputStream in;\n\n    private OutputStream out;\n\n    private OpCode continuousOpCode = null;\n\n    private final List<WebSocketFrame> continuousFrames = new LinkedList<WebSocketFrame>();\n\n    private State state = State.UNCONNECTED;\n\n    protected boolean enforceNoGzip = true;\n\n    private final IHTTPSession handshakeRequest;\n\n    private final Response handshakeResponse = new Response(Status.SWITCH_PROTOCOL, null, (InputStream) null, 0) {\n\n        @Override\n        public void send(OutputStream out) {\n            WebSocket.this.out = out;\n            WebSocket.this.state = State.CONNECTING;\n            super.send(out);\n            WebSocket.this.state = State.OPEN;\n            WebSocket.this.onOpen();\n            readWebsocket();\n        }\n    };\n\n    public WebSocket(IHTTPSession handshakeRequest) {\n        this.handshakeRequest = handshakeRequest;\n        this.in = handshakeRequest.getInputStream();\n        if (enforceNoGzip)\n            handshakeResponse.setUseGzip(false);\n        this.handshakeResponse.addHeader(NanoWSD.HEADER_UPGRADE, NanoWSD.HEADER_UPGRADE_VALUE);\n        this.handshakeResponse.addHeader(NanoWSD.HEADER_CONNECTION, NanoWSD.HEADER_CONNECTION_VALUE);\n    }\n\n    public boolean isOpen() {\n        return state == State.OPEN;\n    }\n\n    protected abstract void onOpen();\n\n    protected abstract void onClose(CloseCode code, String reason, boolean initiatedByRemote);\n\n    protected abstract void onMessage(WebSocketFrame message);\n\n    protected abstract void onPong(WebSocketFrame pong);\n\n    protected abstract void onException(IOException exception);\n\n    /**\n     * Debug method. <b>Do not Override unless for debug purposes!</b>\n     * \n     * @param frame\n     *            The received WebSocket Frame.\n     */\n    protected void debugFrameReceived(WebSocketFrame frame) {\n    }\n\n    /**\n     * Debug method. <b>Do not Override unless for debug purposes!</b><br>\n     * This method is called before actually sending the frame.\n     * \n     * @param frame\n     *            The sent WebSocket Frame.\n     */\n    protected void debugFrameSent(WebSocketFrame frame) {\n    }\n\n    public void close(CloseCode code, String reason, boolean initiatedByRemote) throws IOException {\n        State oldState = this.state;\n        this.state = State.CLOSING;\n        if (oldState == State.OPEN) {\n            sendFrame(new CloseFrame(code, reason));\n        } else {\n            doClose(code, reason, initiatedByRemote);\n        }\n    }\n\n    private void doClose(CloseCode code, String reason, boolean initiatedByRemote) {\n        if (this.state == State.CLOSED) {\n            return;\n        }\n        if (this.in != null) {\n            try {\n                this.in.close();\n            } catch (IOException e) {\n                NanoWSD.LOG.log(Level.FINE, \"close failed\", e);\n            }\n        }\n        if (this.out != null) {\n            try {\n                this.out.close();\n            } catch (IOException e) {\n                NanoWSD.LOG.log(Level.FINE, \"close failed\", e);\n            }\n        }\n        this.state = State.CLOSED;\n        onClose(code, reason, initiatedByRemote);\n    }\n\n    // --------------------------------IO--------------------------------------\n\n    public IHTTPSession getHandshakeRequest() {\n        return this.handshakeRequest;\n    }\n\n    public Response getHandshakeResponse() {\n        return this.handshakeResponse;\n    }\n\n    private void handleCloseFrame(WebSocketFrame frame) throws IOException {\n        CloseCode code = CloseCode.NormalClosure;\n        String reason = \"\";\n        if (frame instanceof CloseFrame) {\n            code = ((CloseFrame) frame).getCloseCode();\n            reason = ((CloseFrame) frame).getCloseReason();\n        }\n        if (this.state == State.CLOSING) {\n            // Answer for my requested close\n            doClose(code, reason, false);\n        } else {\n            close(code, reason, true);\n        }\n    }\n\n    private void handleFrameFragment(WebSocketFrame frame) throws IOException {\n        if (frame.getOpCode() != OpCode.Continuation) {\n            // First\n            if (this.continuousOpCode != null) {\n                throw new WebSocketException(CloseCode.ProtocolError, \"Previous continuous frame sequence not completed.\");\n            }\n            this.continuousOpCode = frame.getOpCode();\n            this.continuousFrames.clear();\n            this.continuousFrames.add(frame);\n        } else if (frame.isFin()) {\n            // Last\n            if (this.continuousOpCode == null) {\n                throw new WebSocketException(CloseCode.ProtocolError, \"Continuous frame sequence was not started.\");\n            }\n            this.continuousFrames.add(frame);\n            onMessage(new WebSocketFrame(this.continuousOpCode, this.continuousFrames));\n            this.continuousOpCode = null;\n            this.continuousFrames.clear();\n        } else if (this.continuousOpCode == null) {\n            // Unexpected\n            throw new WebSocketException(CloseCode.ProtocolError, \"Continuous frame sequence was not started.\");\n        } else {\n            // Intermediate\n            this.continuousFrames.add(frame);\n        }\n    }\n\n    private void handleWebsocketFrame(WebSocketFrame frame) throws IOException {\n        debugFrameReceived(frame);\n        if (frame.getOpCode() == OpCode.Close) {\n            handleCloseFrame(frame);\n        } else if (frame.getOpCode() == OpCode.Ping) {\n            sendFrame(new WebSocketFrame(OpCode.Pong, true, frame.getBinaryPayload()));\n        } else if (frame.getOpCode() == OpCode.Pong) {\n            onPong(frame);\n        } else if (!frame.isFin() || frame.getOpCode() == OpCode.Continuation) {\n            handleFrameFragment(frame);\n        } else if (this.continuousOpCode != null) {\n            throw new WebSocketException(CloseCode.ProtocolError, \"Continuous frame sequence not completed.\");\n        } else if (frame.getOpCode() == OpCode.Text || frame.getOpCode() == OpCode.Binary) {\n            onMessage(frame);\n        } else {\n            throw new WebSocketException(CloseCode.ProtocolError, \"Non control or continuous frame expected.\");\n        }\n    }\n\n    // --------------------------------Close-----------------------------------\n\n    public void ping(byte[] payload) throws IOException {\n        sendFrame(new WebSocketFrame(OpCode.Ping, true, payload));\n    }\n\n    // --------------------------------Public\n    // Facade---------------------------\n\n    private void readWebsocket() {\n        try {\n            while (this.state == State.OPEN) {\n                handleWebsocketFrame(WebSocketFrame.read(this.in));\n            }\n        } catch (CharacterCodingException e) {\n            onException(e);\n            doClose(CloseCode.InvalidFramePayloadData, e.toString(), false);\n        } catch (IOException e) {\n            onException(e);\n            if (e instanceof WebSocketException) {\n                doClose(((WebSocketException) e).getCode(), ((WebSocketException) e).getReason(), false);\n            }\n        } finally {\n            doClose(CloseCode.InternalServerError, \"Handler terminated without closing the connection.\", false);\n        }\n    }\n\n    public void send(byte[] payload) throws IOException {\n        sendFrame(new WebSocketFrame(OpCode.Binary, true, payload));\n    }\n\n    public void send(String payload) throws IOException {\n        sendFrame(new WebSocketFrame(OpCode.Text, true, payload));\n    }\n\n    public synchronized void sendFrame(WebSocketFrame frame) throws IOException {\n        debugFrameSent(frame);\n        frame.write(this.out);\n    }\n}\n"
  },
  {
    "path": "websocket/src/main/java/org/nanohttpd/protocols/websockets/WebSocketException.java",
    "content": "package org.nanohttpd.protocols.websockets;\n\n/*\n * #%L\n * NanoHttpd-Websocket\n * %%\n * Copyright (C) 2012 - 2016 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport java.io.IOException;\n\npublic class WebSocketException extends IOException {\n\n    private static final long serialVersionUID = 1L;\n\n    private final CloseCode code;\n\n    private final String reason;\n\n    public WebSocketException(CloseCode code, String reason) {\n        this(code, reason, null);\n    }\n\n    public WebSocketException(CloseCode code, String reason, Exception cause) {\n        super(code + \": \" + reason, cause);\n        this.code = code;\n        this.reason = reason;\n    }\n\n    public WebSocketException(Exception cause) {\n        this(CloseCode.InternalServerError, cause.toString(), cause);\n    }\n\n    public CloseCode getCode() {\n        return this.code;\n    }\n\n    public String getReason() {\n        return this.reason;\n    }\n}\n"
  },
  {
    "path": "websocket/src/main/java/org/nanohttpd/protocols/websockets/WebSocketFrame.java",
    "content": "package org.nanohttpd.protocols.websockets;\n\n/*\n * #%L\n * NanoHttpd-Websocket\n * %%\n * Copyright (C) 2012 - 2016 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport java.io.EOFException;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.nio.charset.CharacterCodingException;\nimport java.nio.charset.Charset;\nimport java.util.Arrays;\nimport java.util.List;\n\npublic class WebSocketFrame {\n\n    public static final Charset TEXT_CHARSET = Charset.forName(\"UTF-8\");\n\n    public static String binary2Text(byte[] payload) throws CharacterCodingException {\n        return new String(payload, WebSocketFrame.TEXT_CHARSET);\n    }\n\n    public static String binary2Text(byte[] payload, int offset, int length) throws CharacterCodingException {\n        return new String(payload, offset, length, WebSocketFrame.TEXT_CHARSET);\n    }\n\n    private static int checkedRead(int read) throws IOException {\n        if (read < 0) {\n            throw new EOFException();\n        }\n        return read;\n    }\n\n    public static WebSocketFrame read(InputStream in) throws IOException {\n        byte head = (byte) checkedRead(in.read());\n        boolean fin = (head & 0x80) != 0;\n        OpCode opCode = OpCode.find((byte) (head & 0x0F));\n        if ((head & 0x70) != 0) {\n            throw new WebSocketException(CloseCode.ProtocolError, \"The reserved bits (\" + Integer.toBinaryString(head & 0x70) + \") must be 0.\");\n        }\n        if (opCode == null) {\n            throw new WebSocketException(CloseCode.ProtocolError, \"Received frame with reserved/unknown opcode \" + (head & 0x0F) + \".\");\n        } else if (opCode.isControlFrame() && !fin) {\n            throw new WebSocketException(CloseCode.ProtocolError, \"Fragmented control frame.\");\n        }\n\n        WebSocketFrame frame = new WebSocketFrame(opCode, fin);\n        frame.readPayloadInfo(in);\n        frame.readPayload(in);\n        if (frame.getOpCode() == OpCode.Close) {\n            return new CloseFrame(frame);\n        } else {\n            return frame;\n        }\n    }\n\n    public static byte[] text2Binary(String payload) throws CharacterCodingException {\n        return payload.getBytes(WebSocketFrame.TEXT_CHARSET);\n    }\n\n    private OpCode opCode;\n\n    private boolean fin;\n\n    private byte[] maskingKey;\n\n    private byte[] payload;\n\n    // --------------------------------GETTERS---------------------------------\n\n    private transient int _payloadLength;\n\n    private transient String _payloadString;\n\n    private WebSocketFrame(OpCode opCode, boolean fin) {\n        setOpCode(opCode);\n        setFin(fin);\n    }\n\n    public WebSocketFrame(OpCode opCode, boolean fin, byte[] payload) {\n        this(opCode, fin, payload, null);\n    }\n\n    public WebSocketFrame(OpCode opCode, boolean fin, byte[] payload, byte[] maskingKey) {\n        this(opCode, fin);\n        setMaskingKey(maskingKey);\n        setBinaryPayload(payload);\n    }\n\n    public WebSocketFrame(OpCode opCode, boolean fin, String payload) throws CharacterCodingException {\n        this(opCode, fin, payload, null);\n    }\n\n    public WebSocketFrame(OpCode opCode, boolean fin, String payload, byte[] maskingKey) throws CharacterCodingException {\n        this(opCode, fin);\n        setMaskingKey(maskingKey);\n        setTextPayload(payload);\n    }\n\n    public WebSocketFrame(OpCode opCode, List<WebSocketFrame> fragments) throws WebSocketException {\n        setOpCode(opCode);\n        setFin(true);\n\n        long _payloadLength = 0;\n        for (WebSocketFrame inter : fragments) {\n            _payloadLength += inter.getBinaryPayload().length;\n        }\n        if (_payloadLength < 0 || _payloadLength > Integer.MAX_VALUE) {\n            throw new WebSocketException(CloseCode.MessageTooBig, \"Max frame length has been exceeded.\");\n        }\n        this._payloadLength = (int) _payloadLength;\n        byte[] payload = new byte[this._payloadLength];\n        int offset = 0;\n        for (WebSocketFrame inter : fragments) {\n            System.arraycopy(inter.getBinaryPayload(), 0, payload, offset, inter.getBinaryPayload().length);\n            offset += inter.getBinaryPayload().length;\n        }\n        setBinaryPayload(payload);\n    }\n\n    public WebSocketFrame(WebSocketFrame clone) {\n        setOpCode(clone.getOpCode());\n        setFin(clone.isFin());\n        setBinaryPayload(clone.getBinaryPayload());\n        setMaskingKey(clone.getMaskingKey());\n    }\n\n    public byte[] getBinaryPayload() {\n        return this.payload;\n    }\n\n    public byte[] getMaskingKey() {\n        return this.maskingKey;\n    }\n\n    public OpCode getOpCode() {\n        return this.opCode;\n    }\n\n    // --------------------------------SERIALIZATION---------------------------\n\n    public String getTextPayload() {\n        if (this._payloadString == null) {\n            try {\n                this._payloadString = binary2Text(getBinaryPayload());\n            } catch (CharacterCodingException e) {\n                throw new RuntimeException(\"Undetected CharacterCodingException\", e);\n            }\n        }\n        return this._payloadString;\n    }\n\n    public boolean isFin() {\n        return this.fin;\n    }\n\n    public boolean isMasked() {\n        return this.maskingKey != null && this.maskingKey.length == 4;\n    }\n\n    private String payloadToString() {\n        if (this.payload == null) {\n            return \"null\";\n        } else {\n            final StringBuilder sb = new StringBuilder();\n            sb.append('[').append(this.payload.length).append(\"b] \");\n            if (getOpCode() == OpCode.Text) {\n                String text = getTextPayload();\n                if (text.length() > 100) {\n                    sb.append(text.substring(0, 100)).append(\"...\");\n                } else {\n                    sb.append(text);\n                }\n            } else {\n                sb.append(\"0x\");\n                for (int i = 0; i < Math.min(this.payload.length, 50); ++i) {\n                    sb.append(Integer.toHexString(this.payload[i] & 0xFF));\n                }\n                if (this.payload.length > 50) {\n                    sb.append(\"...\");\n                }\n            }\n            return sb.toString();\n        }\n    }\n\n    private void readPayload(InputStream in) throws IOException {\n        this.payload = new byte[this._payloadLength];\n        int read = 0;\n        while (read < this._payloadLength) {\n            read += checkedRead(in.read(this.payload, read, this._payloadLength - read));\n        }\n\n        if (isMasked()) {\n            for (int i = 0; i < this.payload.length; i++) {\n                this.payload[i] ^= this.maskingKey[i % 4];\n            }\n        }\n\n        // Test for Unicode errors\n        if (getOpCode() == OpCode.Text) {\n            this._payloadString = binary2Text(getBinaryPayload());\n        }\n    }\n\n    // --------------------------------ENCODING--------------------------------\n\n    private void readPayloadInfo(InputStream in) throws IOException {\n        byte b = (byte) checkedRead(in.read());\n        boolean masked = (b & 0x80) != 0;\n\n        this._payloadLength = (byte) (0x7F & b);\n        if (this._payloadLength == 126) {\n            // checkedRead must return int for this to work\n            this._payloadLength = (checkedRead(in.read()) << 8 | checkedRead(in.read())) & 0xFFFF;\n            if (this._payloadLength < 126) {\n                throw new WebSocketException(CloseCode.ProtocolError, \"Invalid data frame 2byte length. (not using minimal length encoding)\");\n            }\n        } else if (this._payloadLength == 127) {\n            long _payloadLength =\n                    (long) checkedRead(in.read()) << 56 | (long) checkedRead(in.read()) << 48 | (long) checkedRead(in.read()) << 40 | (long) checkedRead(in.read()) << 32\n                            | checkedRead(in.read()) << 24 | checkedRead(in.read()) << 16 | checkedRead(in.read()) << 8 | checkedRead(in.read());\n            if (_payloadLength < 65536) {\n                throw new WebSocketException(CloseCode.ProtocolError, \"Invalid data frame 4byte length. (not using minimal length encoding)\");\n            }\n            if (_payloadLength < 0 || _payloadLength > Integer.MAX_VALUE) {\n                throw new WebSocketException(CloseCode.MessageTooBig, \"Max frame length has been exceeded.\");\n            }\n            this._payloadLength = (int) _payloadLength;\n        }\n\n        if (this.opCode.isControlFrame()) {\n            if (this._payloadLength > 125) {\n                throw new WebSocketException(CloseCode.ProtocolError, \"Control frame with payload length > 125 bytes.\");\n            }\n            if (this.opCode == OpCode.Close && this._payloadLength == 1) {\n                throw new WebSocketException(CloseCode.ProtocolError, \"Received close frame with payload len 1.\");\n            }\n        }\n\n        if (masked) {\n            this.maskingKey = new byte[4];\n            int read = 0;\n            while (read < this.maskingKey.length) {\n                read += checkedRead(in.read(this.maskingKey, read, this.maskingKey.length - read));\n            }\n        }\n    }\n\n    public void setBinaryPayload(byte[] payload) {\n        this.payload = payload;\n        this._payloadLength = payload.length;\n        this._payloadString = null;\n    }\n\n    public void setFin(boolean fin) {\n        this.fin = fin;\n    }\n\n    public void setMaskingKey(byte[] maskingKey) {\n        if (maskingKey != null && maskingKey.length != 4) {\n            throw new IllegalArgumentException(\"MaskingKey \" + Arrays.toString(maskingKey) + \" hasn't length 4\");\n        }\n        this.maskingKey = maskingKey;\n    }\n\n    public void setOpCode(OpCode opcode) {\n        this.opCode = opcode;\n    }\n\n    public void setTextPayload(String payload) throws CharacterCodingException {\n        this.payload = text2Binary(payload);\n        this._payloadLength = payload.length();\n        this._payloadString = payload;\n    }\n\n    // --------------------------------CONSTANTS-------------------------------\n\n    public void setUnmasked() {\n        setMaskingKey(null);\n    }\n\n    @Override\n    public String toString() {\n        final StringBuilder sb = new StringBuilder(\"WS[\");\n        sb.append(getOpCode());\n        sb.append(\", \").append(isFin() ? \"fin\" : \"inter\");\n        sb.append(\", \").append(isMasked() ? \"masked\" : \"unmasked\");\n        sb.append(\", \").append(payloadToString());\n        sb.append(']');\n        return sb.toString();\n    }\n\n    // ------------------------------------------------------------------------\n\n    public void write(OutputStream out) throws IOException {\n        byte header = 0;\n        if (this.fin) {\n            header |= 0x80;\n        }\n        header |= this.opCode.getValue() & 0x0F;\n        out.write(header);\n\n        this._payloadLength = getBinaryPayload().length;\n        if (this._payloadLength <= 125) {\n            out.write(isMasked() ? 0x80 | (byte) this._payloadLength : (byte) this._payloadLength);\n        } else if (this._payloadLength <= 0xFFFF) {\n            out.write(isMasked() ? 0xFE : 126);\n            out.write(this._payloadLength >>> 8);\n            out.write(this._payloadLength);\n        } else {\n            out.write(isMasked() ? 0xFF : 127);\n            out.write(this._payloadLength >>> 56 & 0); // integer only\n                                                       // contains\n            // 31 bit\n            out.write(this._payloadLength >>> 48 & 0);\n            out.write(this._payloadLength >>> 40 & 0);\n            out.write(this._payloadLength >>> 32 & 0);\n            out.write(this._payloadLength >>> 24);\n            out.write(this._payloadLength >>> 16);\n            out.write(this._payloadLength >>> 8);\n            out.write(this._payloadLength);\n        }\n\n        if (isMasked()) {\n            out.write(this.maskingKey);\n            for (int i = 0; i < this._payloadLength; i++) {\n                out.write(getBinaryPayload()[i] ^ this.maskingKey[i % 4]);\n            }\n        } else {\n            out.write(getBinaryPayload());\n        }\n        out.flush();\n    }\n}\n"
  },
  {
    "path": "websocket/src/main/java/org/nanohttpd/samples/websockets/DebugWebSocketServer.java",
    "content": "package org.nanohttpd.samples.websockets;\n\n/*\n * #%L\n * NanoHttpd-Websocket\n * %%\n * Copyright (C) 2012 - 2015 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport java.io.IOException;\nimport java.util.logging.Level;\nimport java.util.logging.Logger;\n\nimport org.nanohttpd.protocols.http.IHTTPSession;\nimport org.nanohttpd.protocols.websockets.CloseCode;\nimport org.nanohttpd.protocols.websockets.NanoWSD;\nimport org.nanohttpd.protocols.websockets.WebSocket;\nimport org.nanohttpd.protocols.websockets.WebSocketFrame;\n\n/**\n * @author Paul S. Hawke (paul.hawke@gmail.com) On: 4/23/14 at 10:31 PM\n */\npublic class DebugWebSocketServer extends NanoWSD {\n\n    /**\n     * logger to log to.\n     */\n    private static final Logger LOG = Logger.getLogger(DebugWebSocketServer.class.getName());\n\n    private final boolean debug;\n\n    public DebugWebSocketServer(int port, boolean debug) {\n        super(port);\n        this.debug = debug;\n    }\n\n    @Override\n    protected WebSocket openWebSocket(IHTTPSession handshake) {\n        return new DebugWebSocket(this, handshake);\n    }\n\n    private static class DebugWebSocket extends WebSocket {\n\n        private final DebugWebSocketServer server;\n\n        public DebugWebSocket(DebugWebSocketServer server, IHTTPSession handshakeRequest) {\n            super(handshakeRequest);\n            this.server = server;\n        }\n\n        @Override\n        protected void onOpen() {\n        }\n\n        @Override\n        protected void onClose(CloseCode code, String reason, boolean initiatedByRemote) {\n            if (server.debug) {\n                System.out.println(\"C [\" + (initiatedByRemote ? \"Remote\" : \"Self\") + \"] \" + (code != null ? code : \"UnknownCloseCode[\" + code + \"]\")\n                        + (reason != null && !reason.isEmpty() ? \": \" + reason : \"\"));\n            }\n        }\n\n        @Override\n        protected void onMessage(WebSocketFrame message) {\n            try {\n                message.setUnmasked();\n                sendFrame(message);\n            } catch (IOException e) {\n                throw new RuntimeException(e);\n            }\n        }\n\n        @Override\n        protected void onPong(WebSocketFrame pong) {\n            if (server.debug) {\n                System.out.println(\"P \" + pong);\n            }\n        }\n\n        @Override\n        protected void onException(IOException exception) {\n            DebugWebSocketServer.LOG.log(Level.SEVERE, \"exception occured\", exception);\n        }\n\n        @Override\n        protected void debugFrameReceived(WebSocketFrame frame) {\n            if (server.debug) {\n                System.out.println(\"R \" + frame);\n            }\n        }\n\n        @Override\n        protected void debugFrameSent(WebSocketFrame frame) {\n            if (server.debug) {\n                System.out.println(\"S \" + frame);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "websocket/src/main/java/org/nanohttpd/samples/websockets/EchoSocketSample.java",
    "content": "package org.nanohttpd.samples.websockets;\n\n/*\n * #%L\n * NanoHttpd-Websocket\n * %%\n * Copyright (C) 2012 - 2015 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport java.io.IOException;\n\nimport org.nanohttpd.protocols.websockets.NanoWSD;\n\npublic class EchoSocketSample {\n\n    public static void main(String[] args) throws IOException {\n        final boolean debugMode = args.length >= 2 && \"-d\".equals(args[1].toLowerCase());\n        NanoWSD ws = new DebugWebSocketServer(args.length > 0 ? Integer.parseInt(args[0]) : 9090, debugMode);\n        ws.start();\n        System.out.println(\"Server started, hit Enter to stop.\\n\");\n        try {\n            System.in.read();\n        } catch (IOException ignored) {\n        }\n        ws.stop();\n        System.out.println(\"Server stopped.\\n\");\n    }\n\n}\n"
  },
  {
    "path": "websocket/src/site/site.xml",
    "content": "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n<project name=\"${project.name}\">\n\t<skin>\n\t\t<groupId>org.apache.maven.skins</groupId>\n\t\t<artifactId>maven-fluido-skin</artifactId>\n\t\t<version>1.3.0</version>\n\t</skin>\n\t<bannerLeft>\n\t\t<src>../images/nanohttpd_logo.png</src>\n\t</bannerLeft>\n\t<bannerRight>\n\t\t<src>../images/nanohttpd_logo_text.png</src>\n\t</bannerRight>\n\t<publishDate position=\"left\" format=\"yyyy-MM-dd\" />\n\t<version position=\"right\" />\n\t<poweredBy>\n\t\t<logo name=\"Maven\" href=\"http://maven.apache.org/\"\n\t\t\timg=\"http://maven.apache.org/images/logos/maven-feather.png\" />\n\t</poweredBy>\n\t<custom>\n\t\t<fluidoSkin>\n\t\t\t<topBarEnabled>false</topBarEnabled>\n\t\t\t<sideBarEnabled>true</sideBarEnabled>\n\t\t\t<gitHub>\n\t\t\t\t<projectId>Nanohttpd/nanohttpd</projectId>\n\t\t\t\t<ribbonOrientation>right</ribbonOrientation>\n\t\t\t\t<ribbonColor>black</ribbonColor>\n\t\t\t</gitHub>\n\t\t</fluidoSkin>\n\t</custom>\n\t<body>\n\t\t<breadcrumbs>\n\t\t\t<item name=\"${project.name}\" href=\"index.html\" />\n\t\t</breadcrumbs>\n\t\t<menu name=\"Documentation\">\n\t\t\t<item name=\"About\" href=\"index.html\" />\n\t\t</menu>\n\t\t<menu ref=\"modules\" />\n\t\t<menu ref=\"reports\" />\n\t</body>\n</project>"
  },
  {
    "path": "websocket/src/test/java/org/nanohttpd/junit/protocols/websockets/EchoWebSocketsTest.java",
    "content": "package org.nanohttpd.junit.protocols.websockets;\n\n/*\n * #%L\n * NanoHttpd-Websocket\n * %%\n * Copyright (C) 2012 - 2015 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport static org.junit.Assert.assertFalse;\nimport static org.junit.Assert.fail;\n\nimport java.io.IOException;\nimport java.io.PipedInputStream;\nimport java.io.PipedOutputStream;\nimport java.net.URI;\nimport java.util.concurrent.TimeUnit;\n\nimport org.eclipse.jetty.websocket.client.ClientUpgradeRequest;\nimport org.eclipse.jetty.websocket.client.WebSocketClient;\nimport org.junit.AfterClass;\nimport org.junit.Assert;\nimport org.junit.BeforeClass;\nimport org.junit.Test;\nimport org.nanohttpd.protocols.websockets.NanoWSD;\nimport org.nanohttpd.samples.websockets.DebugWebSocketServer;\nimport org.nanohttpd.samples.websockets.EchoSocketSample;\n\npublic class EchoWebSocketsTest {\n\n    private static NanoWSD server;\n\n    @BeforeClass\n    public static void setUp() throws Exception {\n        EchoWebSocketsTest.server = new DebugWebSocketServer(9191, true);\n        EchoWebSocketsTest.server.start();\n    }\n\n    @AfterClass\n    public static void tearDown() throws Exception {\n        EchoWebSocketsTest.server.stop();\n    }\n\n    @Test\n    public void testDirectoryArgument() throws IOException, InterruptedException {\n        final String testPort = \"9458\";\n\n        PipedOutputStream stdIn = new PipedOutputStream();\n        System.setIn(new PipedInputStream(stdIn));\n\n        Thread testServer = new Thread(new Runnable() {\n\n            @Override\n            public void run() {\n                String[] args = {\n                    testPort,\n                    \"-d\"\n                };\n                try {\n                    EchoSocketSample.main(args);\n                } catch (IOException e) {\n                    fail(\"Exception: \" + e.getMessage());\n                }\n            }\n        });\n\n        testServer.start();\n        Thread.sleep(1000);\n        stdIn.write(System.getProperty(\"line.separator\").getBytes());\n        testServer.join(1000);\n        assertFalse(\"Test server failed to close\", testServer.isAlive());\n    }\n\n    @Test\n    public void testWebsocketClient() throws Exception {\n        String destUri = \"ws://localhost:9191\";\n\n        WebSocketClient client = new WebSocketClient();\n        SimpleEchoSocket socket = new SimpleEchoSocket();\n        socket.getToSendMessages().add(\"Hello\");\n        socket.getToSendMessages().add(\"Thanks for the conversation.\");\n        socket.getToSendMessages().add(createString(31000));\n        socket.getToSendMessages().add(createString(65400));\n        try {\n            client.start();\n            URI echoUri = new URI(destUri);\n            ClientUpgradeRequest request = new ClientUpgradeRequest();\n            client.connect(socket, echoUri, request);\n            System.out.printf(\"Connecting to : %s%n\", echoUri);\n            socket.awaitClose(5, TimeUnit.SECONDS);\n        } catch (Throwable t) {\n            t.printStackTrace();\n        } finally {\n            try {\n                client.stop();\n            } catch (Exception e) {\n                e.printStackTrace();\n            }\n        }\n        Assert.assertEquals(4, socket.getReceivedMessages().size());\n        Assert.assertEquals(\"Hello\", socket.getReceivedMessages().get(0));\n        Assert.assertEquals(\"Thanks for the conversation.\", socket.getReceivedMessages().get(1));\n\n    }\n\n    private String createString(int i) {\n        StringBuilder builder = new StringBuilder();\n        while (builder.length() < i) {\n            builder.append(\"A very long text.\");\n        }\n        return builder.toString();\n    }\n}\n"
  },
  {
    "path": "websocket/src/test/java/org/nanohttpd/junit/protocols/websockets/SimpleEchoSocket.java",
    "content": "package org.nanohttpd.junit.protocols.websockets;\n\n/*\n * #%L\n * NanoHttpd-Websocket\n * %%\n * Copyright (C) 2012 - 2015 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.Future;\nimport java.util.concurrent.TimeUnit;\n\nimport org.eclipse.jetty.websocket.api.Session;\nimport org.eclipse.jetty.websocket.api.StatusCode;\nimport org.eclipse.jetty.websocket.api.annotations.OnWebSocketClose;\nimport org.eclipse.jetty.websocket.api.annotations.OnWebSocketConnect;\nimport org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;\nimport org.eclipse.jetty.websocket.api.annotations.WebSocket;\n\n/**\n * Basic Echo Client Socket\n */\n@WebSocket(maxTextMessageSize = 64 * 1024)\npublic class SimpleEchoSocket {\n\n    private final List<String> receivedMessages = new ArrayList<String>();\n\n    private final List<String> toSendMessages = new ArrayList<String>();\n\n    private final CountDownLatch closeLatch;\n\n    public SimpleEchoSocket() {\n        this.closeLatch = new CountDownLatch(1);\n    }\n\n    public boolean awaitClose(int duration, TimeUnit unit) throws InterruptedException {\n        return this.closeLatch.await(duration, unit);\n    }\n\n    public List<String> getReceivedMessages() {\n        return this.receivedMessages;\n    }\n\n    public List<String> getToSendMessages() {\n        return this.toSendMessages;\n    }\n\n    @OnWebSocketClose\n    public void onClose(int statusCode, String reason) {\n        System.out.printf(\"Connection closed: %d - %s%n\", statusCode, reason);\n        this.closeLatch.countDown();\n    }\n\n    @OnWebSocketConnect\n    public void onConnect(Session session) {\n        System.out.printf(\"Got connect: %s%n\", session);\n        try {\n            Future<Void> fut;\n\n            for (String message : this.toSendMessages) {\n                fut = session.getRemote().sendStringByFuture(message);\n                fut.get(5, TimeUnit.SECONDS);\n            }\n            session.close(StatusCode.NORMAL, \"I'm done\");\n        } catch (Throwable t) {\n            t.printStackTrace();\n        }\n    }\n\n    @OnWebSocketMessage\n    public void onMessage(String msg) {\n        System.out.printf(\"Got msg: %s%n\", msg);\n        this.receivedMessages.add(msg);\n    }\n}\n"
  },
  {
    "path": "websocket/src/test/java/org/nanohttpd/junit/protocols/websockets/WebSocketResponseHandlerTest.java",
    "content": "package org.nanohttpd.junit.protocols.websockets;\n\n/*\n * #%L\n * NanoHttpd-Websocket\n * %%\n * Copyright (C) 2012 - 2015 nanohttpd\n * %%\n * Redistribution and use in source and binary forms, with or without modification,\n * are permitted provided that the following conditions are met:\n * \n * 1. Redistributions of source code must retain the above copyright notice, this\n *    list of conditions and the following disclaimer.\n * \n * 2. Redistributions in binary form must reproduce the above copyright notice,\n *    this list of conditions and the following disclaimer in the documentation\n *    and/or other materials provided with the distribution.\n * \n * 3. Neither the name of the nanohttpd nor the names of its contributors\n *    may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n * OF THE POSSIBILITY OF SUCH DAMAGE.\n * #L%\n */\n\nimport static junit.framework.Assert.assertEquals;\nimport static junit.framework.Assert.assertNotNull;\nimport static junit.framework.Assert.assertNull;\nimport static org.mockito.Mockito.when;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport org.junit.Assert;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.mockito.Mock;\nimport org.mockito.Mockito;\nimport org.mockito.runners.MockitoJUnitRunner;\nimport org.nanohttpd.protocols.http.IHTTPSession;\nimport org.nanohttpd.protocols.http.response.Response;\nimport org.nanohttpd.protocols.http.response.Status;\nimport org.nanohttpd.protocols.websockets.CloseCode;\nimport org.nanohttpd.protocols.websockets.NanoWSD;\nimport org.nanohttpd.protocols.websockets.OpCode;\nimport org.nanohttpd.protocols.websockets.WebSocket;\nimport org.nanohttpd.protocols.websockets.WebSocketFrame;\nimport org.nanohttpd.util.IHandler;\n\n@RunWith(MockitoJUnitRunner.class)\npublic class WebSocketResponseHandlerTest {\n\n    @Mock\n    private IHTTPSession session;\n\n    private MockedWSD nanoWebSocketServer;\n\n    private Map<String, String> headers;\n\n    private static class MockedWSD extends NanoWSD {\n\n        public MockedWSD(int port) {\n            super(port);\n        }\n\n        public MockedWSD(String hostname, int port) {\n            super(hostname, port);\n        }\n\n        // This is to work around Mockito being a little bitch.\n        public void initialize() {\n            interceptors = new ArrayList<IHandler<IHTTPSession, Response>>();\n            addHTTPInterceptor(new Interceptor());\n\n            setHTTPHandler(new IHandler<IHTTPSession, Response>() {\n\n                @Override\n                public Response handle(IHTTPSession input) {\n                    return serve(input);\n                }\n            });\n        }\n\n        @Override\n        protected WebSocket openWebSocket(IHTTPSession handshake) {\n            return new WebSocket(handshake) { // Dummy websocket inner class.\n\n                @Override\n                protected void onPong(WebSocketFrame pong) {\n                }\n\n                @Override\n                protected void onOpen() {\n                }\n\n                @Override\n                protected void onMessage(WebSocketFrame message) {\n                }\n\n                @Override\n                protected void onException(IOException exception) {\n                }\n\n                @Override\n                protected void onClose(CloseCode code, String reason, boolean initiatedByRemote) {\n                }\n            };\n        }\n    }\n\n    @Before\n    public void setUp() {\n        // Be careful.\n        // This does NOT call any constructors, instead, directly creates\n        // the object in memory. I wasted 3 fucking hours attempting to\n        // debug this. ~ LordFokas\n        this.nanoWebSocketServer = Mockito.mock(MockedWSD.class, Mockito.CALLS_REAL_METHODS);\n        // this could have been avoided if Mockito had a way to call fucking\n        // constructors!!\n        this.nanoWebSocketServer.initialize();\n\n        this.headers = new HashMap<String, String>();\n        this.headers.put(\"upgrade\", \"websocket\");\n        this.headers.put(\"connection\", \"Upgrade\");\n        this.headers.put(\"sec-websocket-key\", \"x3JJHMbDL1EzLkh9GBhXDw==\");\n        this.headers.put(\"sec-websocket-protocol\", \"chat, superchat\");\n        this.headers.put(\"sec-websocket-version\", \"13\");\n\n        when(this.session.getHeaders()).thenReturn(this.headers);\n    }\n\n    @Test\n    public void testConnectionHeaderHandlesKeepAlive_FixingFirefoxConnectIssue() {\n        this.headers.put(\"connection\", \"keep-alive, Upgrade\");\n        Response handshakeResponse = this.nanoWebSocketServer.handle(this.session);\n\n        assertNotNull(handshakeResponse);\n    }\n\n    @Test\n    public void testHandshakeReturnsResponseWithExpectedHeaders() {\n        Response handshakeResponse = this.nanoWebSocketServer.handle(this.session);\n\n        assertNotNull(handshakeResponse);\n\n        assertEquals(handshakeResponse.getHeader(NanoWSD.HEADER_WEBSOCKET_ACCEPT), \"HSmrc0sMlYUkAGmm5OPpG2HaGWk=\");\n        assertEquals(handshakeResponse.getHeader(NanoWSD.HEADER_WEBSOCKET_PROTOCOL), \"chat\");\n    }\n\n    @Test\n    public void testMissingKeyReturnsErrorResponse() {\n        this.headers.remove(\"sec-websocket-key\");\n\n        Response handshakeResponse = this.nanoWebSocketServer.handle(this.session);\n\n        assertNotNull(handshakeResponse);\n        assertEquals(Status.BAD_REQUEST, handshakeResponse.getStatus());\n    }\n\n    @Test\n    public void testWrongConnectionHeaderReturnsNullResponse() {\n        this.headers.put(\"connection\", \"Junk\");\n        Response handshakeResponse = this.nanoWebSocketServer.handle(this.session);\n        assertNull(handshakeResponse.getHeader(NanoWSD.HEADER_UPGRADE));\n    }\n\n    @Test\n    public void testWrongUpgradeHeaderReturnsNullResponse() {\n        this.headers.put(\"upgrade\", \"not a websocket\");\n        Response handshakeResponse = this.nanoWebSocketServer.handle(this.session);\n        assertNull(handshakeResponse.getHeader(NanoWSD.HEADER_UPGRADE));\n    }\n\n    @Test\n    public void testWrongWebsocketVersionReturnsErrorResponse() {\n        this.headers.put(\"sec-websocket-version\", \"12\");\n\n        Response handshakeResponse = this.nanoWebSocketServer.handle(this.session);\n\n        assertNotNull(handshakeResponse);\n        assertEquals(Status.BAD_REQUEST, handshakeResponse.getStatus());\n    }\n\n    @Test\n    public void testSetMaskingKeyThrowsExceptionMaskingKeyLengthIsNotFour() {\n        WebSocketFrame webSocketFrame = new WebSocketFrame(OpCode.Text, true, new byte[0]);\n        for (int maskingKeyLength = 0; maskingKeyLength < 10; maskingKeyLength++) {\n            if (maskingKeyLength == 4)\n                continue;\n            try {\n                webSocketFrame.setMaskingKey(new byte[maskingKeyLength]);\n                Assert.fail(\"IllegalArgumentException expected but not thrown\");\n            } catch (IllegalArgumentException e) {\n\n            }\n        }\n    }\n\n    @Test\n    public void testIsMasked() {\n        WebSocketFrame webSocketFrame = new WebSocketFrame(OpCode.Text, true, new byte[0]);\n        Assert.assertFalse(\"isMasked should return true if masking key is not set.\", webSocketFrame.isMasked());\n\n        webSocketFrame.setMaskingKey(new byte[4]);\n        Assert.assertTrue(\"isMasked should return true if correct masking key is set.\", webSocketFrame.isMasked());\n\n    }\n\n    @Test\n    public void testWriteWhenNotMasked() throws IOException {\n        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();\n        WebSocketFrame webSocketFrame = new WebSocketFrame(OpCode.Text, true, \"payload\".getBytes());\n        webSocketFrame.write(byteArrayOutputStream);\n        byte[] writtenBytes = byteArrayOutputStream.toByteArray();\n        Assert.assertEquals(9, writtenBytes.length);\n        Assert.assertEquals(\"Header byte incorrect.\", -127, writtenBytes[0]);\n        Assert.assertEquals(\"Payload length byte incorrect.\", 7, writtenBytes[1]);\n        Assert.assertArrayEquals(new byte[]{\n            -127,\n            7,\n            112,\n            97,\n            121,\n            108,\n            111,\n            97,\n            100\n        }, writtenBytes);\n    }\n\n    @Test\n    public void testWriteWhenMasked() throws IOException {\n        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();\n        WebSocketFrame webSocketFrame = new WebSocketFrame(OpCode.Binary, true, \"payload\".getBytes());\n        webSocketFrame.setMaskingKey(new byte[]{\n            12,\n            45,\n            33,\n            32\n        });\n        webSocketFrame.write(byteArrayOutputStream);\n        byte[] writtenBytes = byteArrayOutputStream.toByteArray();\n        Assert.assertEquals(13, writtenBytes.length);\n        Assert.assertEquals(\"Header byte incorrect.\", -126, writtenBytes[0]);\n        Assert.assertEquals(\"Payload length byte incorrect.\", -121, writtenBytes[1]);\n        Assert.assertArrayEquals(new byte[]{\n            -126,\n            -121,\n            12,\n            45,\n            33,\n            32,\n            124,\n            76,\n            88,\n            76,\n            99,\n            76,\n            69\n        }, writtenBytes);\n    }\n\n    @Test\n    public void testWriteWhenNotMaskedPayloadLengthGreaterThan125() throws IOException {\n        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();\n        WebSocketFrame webSocketFrame = new WebSocketFrame(OpCode.Ping, true, new byte[257]);\n        webSocketFrame.write(byteArrayOutputStream);\n        byte[] writtenBytes = byteArrayOutputStream.toByteArray();\n        Assert.assertEquals(261, writtenBytes.length);\n        Assert.assertEquals(\"Header byte incorrect.\", -119, writtenBytes[0]);\n        Assert.assertArrayEquals(\"Payload length bytes incorrect.\", new byte[]{\n            126,\n            1,\n            1\n        }, new byte[]{\n            writtenBytes[1],\n            writtenBytes[2],\n            writtenBytes[3]\n        });\n    }\n\n    @Test\n    public void testWriteWhenMaskedPayloadLengthGreaterThan125() throws IOException {\n        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();\n        WebSocketFrame webSocketFrame = new WebSocketFrame(OpCode.Ping, false, new byte[257]);\n        webSocketFrame.setMaskingKey(new byte[]{\n            19,\n            25,\n            79,\n            11\n        });\n        webSocketFrame.write(byteArrayOutputStream);\n        byte[] writtenBytes = byteArrayOutputStream.toByteArray();\n        Assert.assertEquals(265, writtenBytes.length);\n        Assert.assertEquals(\"Header byte incorrect.\", 9, writtenBytes[0]);\n        Assert.assertArrayEquals(\"Payload length bytes incorrect.\", new byte[]{\n            -2,\n            1,\n            1\n        }, new byte[]{\n            writtenBytes[1],\n            writtenBytes[2],\n            writtenBytes[3]\n        });\n    }\n\n    @Test\n    public void testWriteWhenNotMaskedPayloadLengthGreaterThan65535() throws IOException {\n        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();\n        WebSocketFrame webSocketFrame = new WebSocketFrame(OpCode.Ping, true, new byte[65536]);\n        webSocketFrame.write(byteArrayOutputStream);\n        byte[] writtenBytes = byteArrayOutputStream.toByteArray();\n        Assert.assertEquals(65546, writtenBytes.length);\n        Assert.assertEquals(\"Header byte incorrect.\", -119, writtenBytes[0]);\n        Assert.assertArrayEquals(\"Payload length bytes incorrect.\", new byte[]{\n            127,\n            0,\n            0,\n            0,\n            0,\n            0,\n            1,\n            0,\n            0\n        }, Arrays.copyOfRange(writtenBytes, 1, 10));\n    }\n}\n"
  },
  {
    "path": "websocket/src/test/resources/echo-test.html",
    "content": "<!--\n  #%L\n  NanoHttpd-Websocket\n  %%\n  Copyright (C) 2012 - 2015 nanohttpd\n  %%\n  Redistribution and use in source and binary forms, with or without modification,\n  are permitted provided that the following conditions are met:\n  \n  1. Redistributions of source code must retain the above copyright notice, this\n     list of conditions and the following disclaimer.\n  \n  2. Redistributions in binary form must reproduce the above copyright notice,\n     this list of conditions and the following disclaimer in the documentation\n     and/or other materials provided with the distribution.\n  \n  3. Neither the name of the nanohttpd nor the names of its contributors\n     may 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 COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND\n  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n  IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,\n  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,\n  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\n  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\n  OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED\n  OF THE POSSIBILITY OF SUCH DAMAGE.\n  #L%\n  -->\n<html>\n<head>\n    <meta charset=\"utf-8\"/>\n    <title>WebSocket Test</title>\n    <script language=\"javascript\" type=\"text/javascript\">\n        var wsUri = \"ws://localhost:9090/\";\n        var output;\n        function init() {\n            output = document.getElementById(\"output\");\n            testWebSocket();\n        }\n        function testWebSocket() {\n            websocket = new WebSocket(wsUri);\n            websocket.onopen = function (evt) {\n                onOpen(evt)\n            };\n            websocket.onclose = function (evt) {\n                onClose(evt)\n            };\n            websocket.onmessage = function (evt) {\n                onMessage(evt)\n            };\n            websocket.onerror = function (evt) {\n                onError(evt)\n            };\n        }\n        function onOpen(evt) {\n            writeToScreen(\"CONNECTED\");\n            doSend(\"WebSocket rocks\");\n        }\n        function onClose(evt) {\n            writeToScreen(\"DISCONNECTED\");\n        }\n        function onMessage(evt) {\n            writeToScreen('<span style=\"color: blue;\">RESPONSE: ' + evt.data + '</span>');\n            websocket.close();\n        }\n        function onError(evt) {\n            writeToScreen('<span style=\"color: red;\">ERROR:</span> ' + evt.data);\n        }\n        function doSend(message) {\n            writeToScreen(\"SENT: \" + message);\n            websocket.send(message);\n        }\n        function writeToScreen(message) {\n            var pre = document.createElement(\"p\");\n            pre.style.wordWrap = \"break-word\";\n            pre.innerHTML = message;\n            output.appendChild(pre);\n        }\n        window.addEventListener(\"load\", init, false);  </script>\n</head>\n<body>\n<h2>WebSocket Test</h2>\n\n<div id=\"output\"></div>\n</body>\n</html>"
  }
]