mirror of
https://github.com/AtlasMediaGroup/TotalFreedomMod.git
synced 2024-11-27 01:05:38 +00:00
Update NanoHTTPd to 12b4973a52
This commit is contained in:
parent
7b59350833
commit
e10ab45bda
@ -1,5 +1,5 @@
|
|||||||
#Tue, 17 Sep 2013 12:03:45 -0400
|
#Tue, 17 Sep 2013 21:28:11 -0400
|
||||||
|
|
||||||
program.VERSION=3.2
|
program.VERSION=3.2
|
||||||
program.BUILDNUM=595
|
program.BUILDNUM=596
|
||||||
program.BUILDDATE=09/17/2013 12\:03 PM
|
program.BUILDDATE=09/17/2013 09\:28 PM
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
#Build Number for ANT. Do not edit!
|
#Build Number for ANT. Do not edit!
|
||||||
#Tue Sep 17 12:03:45 EDT 2013
|
#Tue Sep 17 21:28:11 EDT 2013
|
||||||
build.number=596
|
build.number=597
|
||||||
|
@ -2,7 +2,6 @@ package me.StevenLawson.TotalFreedomMod.HTTPD;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.Socket;
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
@ -16,9 +15,9 @@ public class Module_dump extends TFM_HTTPD_Module
|
|||||||
private File echoFile = null;
|
private File echoFile = null;
|
||||||
private final String body;
|
private final String body;
|
||||||
|
|
||||||
public Module_dump(String uri, NanoHTTPD.Method method, Map<String, String> headers, Map<String, String> params, Map<String, String> files, Socket socket)
|
public Module_dump(NanoHTTPD.HTTPSession session)
|
||||||
{
|
{
|
||||||
super(uri, method, headers, params, files, socket);
|
super(session);
|
||||||
|
|
||||||
//Body needs to be computed before getResponse, so we know if a text response or a file echo is needed.
|
//Body needs to be computed before getResponse, so we know if a text response or a file echo is needed.
|
||||||
this.body = body();
|
this.body = body();
|
||||||
@ -54,6 +53,8 @@ public class Module_dump extends TFM_HTTPD_Module
|
|||||||
|
|
||||||
String[] args = StringUtils.split(uri, "/");
|
String[] args = StringUtils.split(uri, "/");
|
||||||
|
|
||||||
|
Map<String, String> files = getFiles();
|
||||||
|
|
||||||
responseBody
|
responseBody
|
||||||
.append(paragraph("URI: " + uri))
|
.append(paragraph("URI: " + uri))
|
||||||
.append(paragraph("args (Length: " + args.length + "): " + StringUtils.join(args, ",")))
|
.append(paragraph("args (Length: " + args.length + "): " + StringUtils.join(args, ",")))
|
||||||
|
@ -5,7 +5,6 @@ import java.io.FileInputStream;
|
|||||||
import java.io.FilenameFilter;
|
import java.io.FilenameFilter;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.net.Socket;
|
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@ -13,9 +12,9 @@ import java.util.HashMap;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.StringTokenizer;
|
import java.util.StringTokenizer;
|
||||||
|
import me.StevenLawson.TotalFreedomMod.TFM_ConfigEntry;
|
||||||
|
|
||||||
import static me.StevenLawson.TotalFreedomMod.HTTPD.NanoHTTPD.*;
|
import static me.StevenLawson.TotalFreedomMod.HTTPD.NanoHTTPD.*;
|
||||||
import me.StevenLawson.TotalFreedomMod.TFM_ConfigEntry;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This class was adapted from https://github.com/NanoHttpd/nanohttpd/blob/master/webserver/src/main/java/fi/iki/elonen/SimpleWebServer.java
|
* This class was adapted from https://github.com/NanoHttpd/nanohttpd/blob/master/webserver/src/main/java/fi/iki/elonen/SimpleWebServer.java
|
||||||
@ -55,9 +54,9 @@ public class Module_file extends TFM_HTTPD_Module
|
|||||||
MIME_TYPES.put("class", "application/octet-stream");
|
MIME_TYPES.put("class", "application/octet-stream");
|
||||||
}
|
}
|
||||||
|
|
||||||
public Module_file(String uri, Method method, Map<String, String> headers, Map<String, String> params, Map<String, String> files, Socket socket)
|
public Module_file(NanoHTTPD.HTTPSession session)
|
||||||
{
|
{
|
||||||
super(uri, method, headers, params, files, socket);
|
super(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
private File getRootDir()
|
private File getRootDir()
|
||||||
@ -175,7 +174,7 @@ public class Module_file extends TFM_HTTPD_Module
|
|||||||
}
|
}
|
||||||
if (mime == null)
|
if (mime == null)
|
||||||
{
|
{
|
||||||
mime = NanoHTTPD.MIME_DEFAULT_BINARY;
|
mime = TFM_HTTPD_Manager.MIME_DEFAULT_BINARY;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate etag
|
// Calculate etag
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package me.StevenLawson.TotalFreedomMod.HTTPD;
|
package me.StevenLawson.TotalFreedomMod.HTTPD;
|
||||||
|
|
||||||
import java.net.Socket;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
@ -21,9 +20,9 @@ import static org.apache.commons.lang3.StringEscapeUtils.*;
|
|||||||
|
|
||||||
public class Module_help extends TFM_HTTPD_Module
|
public class Module_help extends TFM_HTTPD_Module
|
||||||
{
|
{
|
||||||
public Module_help(String uri, NanoHTTPD.Method method, Map<String, String> headers, Map<String, String> params, Map<String, String> files, Socket socket)
|
public Module_help(NanoHTTPD.HTTPSession session)
|
||||||
{
|
{
|
||||||
super(uri, method, headers, params, files, socket);
|
super(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
package me.StevenLawson.TotalFreedomMod.HTTPD;
|
package me.StevenLawson.TotalFreedomMod.HTTPD;
|
||||||
|
|
||||||
import java.net.Socket;
|
|
||||||
import java.util.Map;
|
|
||||||
import me.StevenLawson.TotalFreedomMod.TFM_SuperadminList;
|
import me.StevenLawson.TotalFreedomMod.TFM_SuperadminList;
|
||||||
import me.StevenLawson.TotalFreedomMod.TFM_Util;
|
import me.StevenLawson.TotalFreedomMod.TFM_Util;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
@ -9,9 +7,9 @@ import org.bukkit.entity.Player;
|
|||||||
|
|
||||||
public class Module_list extends TFM_HTTPD_Module
|
public class Module_list extends TFM_HTTPD_Module
|
||||||
{
|
{
|
||||||
public Module_list(String uri, NanoHTTPD.Method method, Map<String, String> headers, Map<String, String> params, Map<String, String> files, Socket socket)
|
public Module_list(NanoHTTPD.HTTPSession session)
|
||||||
{
|
{
|
||||||
super(uri, method, headers, params, files, socket);
|
super(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1,15 +1,13 @@
|
|||||||
package me.StevenLawson.TotalFreedomMod.HTTPD;
|
package me.StevenLawson.TotalFreedomMod.HTTPD;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.net.Socket;
|
|
||||||
import java.util.Map;
|
|
||||||
import me.StevenLawson.TotalFreedomMod.TotalFreedomMod;
|
import me.StevenLawson.TotalFreedomMod.TotalFreedomMod;
|
||||||
|
|
||||||
public class Module_permbans extends TFM_HTTPD_Module
|
public class Module_permbans extends TFM_HTTPD_Module
|
||||||
{
|
{
|
||||||
public Module_permbans(String uri, NanoHTTPD.Method method, Map<String, String> headers, Map<String, String> params, Map<String, String> files, Socket socket)
|
public Module_permbans(NanoHTTPD.HTTPSession session)
|
||||||
{
|
{
|
||||||
super(uri, method, headers, params, files, socket);
|
super(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -2,7 +2,6 @@ package me.StevenLawson.TotalFreedomMod.HTTPD;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.Socket;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@ -16,8 +15,8 @@ import me.StevenLawson.TotalFreedomMod.TFM_Log;
|
|||||||
import me.StevenLawson.TotalFreedomMod.TFM_Superadmin;
|
import me.StevenLawson.TotalFreedomMod.TFM_Superadmin;
|
||||||
import me.StevenLawson.TotalFreedomMod.TFM_SuperadminList;
|
import me.StevenLawson.TotalFreedomMod.TFM_SuperadminList;
|
||||||
import org.apache.commons.io.FileUtils;
|
import org.apache.commons.io.FileUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.apache.commons.lang3.StringEscapeUtils;
|
import org.apache.commons.lang3.StringEscapeUtils;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
public class Module_schematic extends TFM_HTTPD_Module
|
public class Module_schematic extends TFM_HTTPD_Module
|
||||||
{
|
{
|
||||||
@ -36,9 +35,9 @@ public class Module_schematic extends TFM_HTTPD_Module
|
|||||||
+ "<button type=\"submit\">Submit</button>\n"
|
+ "<button type=\"submit\">Submit</button>\n"
|
||||||
+ "</form>";
|
+ "</form>";
|
||||||
|
|
||||||
public Module_schematic(String uri, Method method, Map<String, String> headers, Map<String, String> params, Map<String, String> files, Socket socket)
|
public Module_schematic(NanoHTTPD.HTTPSession session)
|
||||||
{
|
{
|
||||||
super(uri, method, headers, params, files, socket);
|
super(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -153,6 +152,8 @@ public class Module_schematic extends TFM_HTTPD_Module
|
|||||||
|
|
||||||
private boolean uploadSchematic() throws SchematicTransferException
|
private boolean uploadSchematic() throws SchematicTransferException
|
||||||
{
|
{
|
||||||
|
Map<String, String> files = getFiles();
|
||||||
|
|
||||||
final String tempFileName = files.get(REQUEST_FORM_FILE_ELEMENT_NAME);
|
final String tempFileName = files.get(REQUEST_FORM_FILE_ELEMENT_NAME);
|
||||||
if (tempFileName == null)
|
if (tempFileName == null)
|
||||||
{
|
{
|
||||||
|
@ -1,11 +1,7 @@
|
|||||||
package me.StevenLawson.TotalFreedomMod.HTTPD;
|
package me.StevenLawson.TotalFreedomMod.HTTPD;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.net.InetSocketAddress;
|
import java.net.*;
|
||||||
import java.net.ServerSocket;
|
|
||||||
import java.net.Socket;
|
|
||||||
import java.net.SocketException;
|
|
||||||
import java.net.URLDecoder;
|
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.channels.FileChannel;
|
import java.nio.channels.FileChannel;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
@ -67,17 +63,21 @@ public abstract class NanoHTTPD
|
|||||||
*/
|
*/
|
||||||
public static final String MIME_HTML = "text/html";
|
public static final String MIME_HTML = "text/html";
|
||||||
/**
|
/**
|
||||||
* Common mime type for dynamic content: binary
|
* Pseudo-Parameter to use to store the actual query string in the parameters map for later re-processing.
|
||||||
*/
|
*/
|
||||||
public static final String MIME_DEFAULT_BINARY = "application/octet-stream";
|
private static final String QUERY_STRING_PARAMETER = "NanoHttpd.QUERY_STRING";
|
||||||
private final String hostname;
|
private final String hostname;
|
||||||
private final int myPort;
|
private final int myPort;
|
||||||
private ServerSocket myServerSocket;
|
private ServerSocket myServerSocket;
|
||||||
private Thread myThread;
|
private Thread myThread;
|
||||||
/**
|
/**
|
||||||
* Pseudo-Parameter to use to store the actual query string in the parameters map for later re-processing.
|
* Pluggable strategy for asynchronously executing requests.
|
||||||
*/
|
*/
|
||||||
private static final String QUERY_STRING_PARAMETER = "NanoHttpd.QUERY_STRING";
|
private AsyncRunner asyncRunner;
|
||||||
|
/**
|
||||||
|
* Pluggable strategy for creating and cleaning up temporary files.
|
||||||
|
*/
|
||||||
|
private TempFileManagerFactory tempFileManagerFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs an HTTP server on given port.
|
* Constructs an HTTP server on given port.
|
||||||
@ -98,8 +98,51 @@ public abstract class NanoHTTPD
|
|||||||
setAsyncRunner(new DefaultAsyncRunner());
|
setAsyncRunner(new DefaultAsyncRunner());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final void safeClose(ServerSocket serverSocket)
|
||||||
|
{
|
||||||
|
if (serverSocket != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
serverSocket.close();
|
||||||
|
}
|
||||||
|
catch (IOException e)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final void safeClose(Socket socket)
|
||||||
|
{
|
||||||
|
if (socket != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
socket.close();
|
||||||
|
}
|
||||||
|
catch (IOException e)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final void safeClose(Closeable closeable)
|
||||||
|
{
|
||||||
|
if (closeable != null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
closeable.close();
|
||||||
|
}
|
||||||
|
catch (IOException e)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start the server.
|
* Start the server.
|
||||||
|
*
|
||||||
* @throws IOException if the socket is in use.
|
* @throws IOException if the socket is in use.
|
||||||
*/
|
*/
|
||||||
public void start() throws IOException
|
public void start() throws IOException
|
||||||
@ -187,20 +230,39 @@ public abstract class NanoHTTPD
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final int getListeningPort()
|
||||||
|
{
|
||||||
|
return myServerSocket == null ? -1 : myServerSocket.getLocalPort();
|
||||||
|
}
|
||||||
|
|
||||||
|
public final boolean wasStarted()
|
||||||
|
{
|
||||||
|
return myServerSocket != null && myThread != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final boolean isAlive()
|
||||||
|
{
|
||||||
|
return wasStarted() && !myServerSocket.isClosed() && myThread.isAlive();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Override this to customize the server.
|
* Override this to customize the server.
|
||||||
* <p/>
|
* <p/>
|
||||||
* <p/>
|
* <p/>
|
||||||
* (By default, this delegates to serveFile() and allows directory listing.)
|
* (By default, this delegates to serveFile() and allows directory listing.)
|
||||||
*
|
*
|
||||||
* @param uri Percent-decoded URI without parameters, for example "/index.cgi"
|
* @param uri Percent-decoded URI without parameters, for example "/index.cgi"
|
||||||
* @param method "GET", "POST" etc.
|
* @param method "GET", "POST" etc.
|
||||||
* @param parms Parsed, percent decoded parameters from URI and, in case of POST, data.
|
* @param parms Parsed, percent decoded parameters from URI and, in case of POST, data.
|
||||||
* @param headers Header entries, percent decoded
|
* @param headers Header entries, percent decoded
|
||||||
* @return HTTP response, see class Response for details
|
* @return HTTP response, see class Response for details
|
||||||
*/
|
*/
|
||||||
public abstract Response serve(String uri, Method method, Map<String, String> headers, Map<String, String> parms,
|
@Deprecated
|
||||||
Map<String, String> files, Socket socket);
|
public Response serve(String uri, Method method, Map<String, String> headers, Map<String, String> parms,
|
||||||
|
Map<String, String> files)
|
||||||
|
{
|
||||||
|
return new Response(Response.Status.NOT_FOUND, MIME_PLAINTEXT, "Not Found");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Override this to customize the server.
|
* Override this to customize the server.
|
||||||
@ -211,33 +273,32 @@ public abstract class NanoHTTPD
|
|||||||
* @param session The HTTP session
|
* @param session The HTTP session
|
||||||
* @return HTTP response, see class Response for details
|
* @return HTTP response, see class Response for details
|
||||||
*/
|
*/
|
||||||
protected Response serve(HTTPSession session)
|
public Response serve(HTTPSession session)
|
||||||
{
|
{
|
||||||
Map<String, String> files = new HashMap<String, String>();
|
Map<String, String> files = new HashMap<String, String>();
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
session.parseBody(files);
|
|
||||||
}
|
|
||||||
catch (IOException ioe)
|
|
||||||
{
|
|
||||||
return new Response(Response.Status.INTERNAL_ERROR, MIME_PLAINTEXT, "SERVER INTERNAL ERROR: IOException: " + ioe.getMessage());
|
|
||||||
}
|
|
||||||
catch (ResponseException re)
|
|
||||||
{
|
|
||||||
return new Response(re.getStatus(), MIME_PLAINTEXT, re.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
String uri = session.getUri();
|
|
||||||
Method method = session.getMethod();
|
Method method = session.getMethod();
|
||||||
Map<String, String> parms = session.getParms();
|
if (Method.PUT.equals(method) || Method.POST.equals(method))
|
||||||
Map<String, String> headers = session.getHeaders();
|
{
|
||||||
Socket socket = session.getSocket();
|
try
|
||||||
return serve(uri, method, headers, parms, files, socket);
|
{
|
||||||
|
session.parseBody(files);
|
||||||
|
}
|
||||||
|
catch (IOException ioe)
|
||||||
|
{
|
||||||
|
return new Response(Response.Status.INTERNAL_ERROR, MIME_PLAINTEXT, "SERVER INTERNAL ERROR: IOException: " + ioe.getMessage());
|
||||||
|
}
|
||||||
|
catch (ResponseException re)
|
||||||
|
{
|
||||||
|
return new Response(re.getStatus(), MIME_PLAINTEXT, re.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return serve(session.getUri(), method, session.getHeaders(), session.getParms(), files);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decode percent encoded <code>String</code> values.
|
* Decode percent encoded <code>String</code> values.
|
||||||
|
*
|
||||||
* @param str the percent encoded <code>String</code>
|
* @param str the percent encoded <code>String</code>
|
||||||
* @return expanded form of the input, for example "foo%20bar" becomes "foo bar"
|
* @return expanded form of the input, for example "foo%20bar" becomes "foo bar"
|
||||||
*/
|
*/
|
||||||
@ -300,6 +361,36 @@ public abstract class NanoHTTPD
|
|||||||
return parms;
|
return parms;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------- //
|
||||||
|
//
|
||||||
|
// Threading Strategy.
|
||||||
|
//
|
||||||
|
// ------------------------------------------------------------------------------- //
|
||||||
|
/**
|
||||||
|
* Pluggable strategy for asynchronously executing requests.
|
||||||
|
*
|
||||||
|
* @param asyncRunner new strategy for handling threads.
|
||||||
|
*/
|
||||||
|
public void setAsyncRunner(AsyncRunner asyncRunner)
|
||||||
|
{
|
||||||
|
this.asyncRunner = asyncRunner;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------- //
|
||||||
|
//
|
||||||
|
// Temp file handling strategy.
|
||||||
|
//
|
||||||
|
// ------------------------------------------------------------------------------- //
|
||||||
|
/**
|
||||||
|
* Pluggable strategy for creating and cleaning up temporary files.
|
||||||
|
*
|
||||||
|
* @param tempFileManagerFactory new strategy for handling temp files.
|
||||||
|
*/
|
||||||
|
public void setTempFileManagerFactory(TempFileManagerFactory tempFileManagerFactory)
|
||||||
|
{
|
||||||
|
this.tempFileManagerFactory = tempFileManagerFactory;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HTTP Request methods, with the ability to decode a <code>String</code> back to its enum value.
|
* HTTP Request methods, with the ability to decode a <code>String</code> back to its enum value.
|
||||||
*/
|
*/
|
||||||
@ -319,24 +410,6 @@ public abstract class NanoHTTPD
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ------------------------------------------------------------------------------- //
|
|
||||||
//
|
|
||||||
// Threading Strategy.
|
|
||||||
//
|
|
||||||
// ------------------------------------------------------------------------------- //
|
|
||||||
/**
|
|
||||||
* Pluggable strategy for asynchronously executing requests.
|
|
||||||
*/
|
|
||||||
private AsyncRunner asyncRunner;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pluggable strategy for asynchronously executing requests.
|
|
||||||
* @param asyncRunner new strategy for handling threads.
|
|
||||||
*/
|
|
||||||
public void setAsyncRunner(AsyncRunner asyncRunner)
|
|
||||||
{
|
|
||||||
this.asyncRunner = asyncRunner;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pluggable strategy for asynchronously executing requests.
|
* Pluggable strategy for asynchronously executing requests.
|
||||||
@ -346,9 +419,46 @@ public abstract class NanoHTTPD
|
|||||||
void exec(Runnable code);
|
void exec(Runnable code);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Factory to create temp file managers.
|
||||||
|
*/
|
||||||
|
public interface TempFileManagerFactory
|
||||||
|
{
|
||||||
|
TempFileManager create();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------------- //
|
||||||
|
/**
|
||||||
|
* Temp file manager.
|
||||||
|
* <p/>
|
||||||
|
* <p>Temp file managers are created 1-to-1 with incoming requests, to create and cleanup
|
||||||
|
* temporary files created as a result of handling the request.</p>
|
||||||
|
*/
|
||||||
|
public interface TempFileManager
|
||||||
|
{
|
||||||
|
TempFile createTempFile() throws Exception;
|
||||||
|
|
||||||
|
void clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A temp file.
|
||||||
|
* <p/>
|
||||||
|
* <p>Temp files are responsible for managing the actual temporary storage and cleaning
|
||||||
|
* themselves up when no longer needed.</p>
|
||||||
|
*/
|
||||||
|
public interface TempFile
|
||||||
|
{
|
||||||
|
OutputStream open() throws Exception;
|
||||||
|
|
||||||
|
void delete() throws Exception;
|
||||||
|
|
||||||
|
String getName();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default threading strategy for NanoHttpd.
|
* Default threading strategy for NanoHttpd.
|
||||||
*
|
* <p/>
|
||||||
* <p>By default, the server spawns a new Thread for every incoming request. These are set
|
* <p>By default, the server spawns a new Thread for every incoming request. These are set
|
||||||
* to <i>daemon</i> status, and named according to the request number. The name is
|
* to <i>daemon</i> status, and named according to the request number. The name is
|
||||||
* useful when profiling the application.</p>
|
* useful when profiling the application.</p>
|
||||||
@ -367,76 +477,10 @@ public abstract class NanoHTTPD
|
|||||||
t.start();
|
t.start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ------------------------------------------------------------------------------- //
|
|
||||||
//
|
|
||||||
// Temp file handling strategy.
|
|
||||||
//
|
|
||||||
// ------------------------------------------------------------------------------- //
|
|
||||||
/**
|
|
||||||
* Pluggable strategy for creating and cleaning up temporary files.
|
|
||||||
*/
|
|
||||||
private TempFileManagerFactory tempFileManagerFactory;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pluggable strategy for creating and cleaning up temporary files.
|
|
||||||
* @param tempFileManagerFactory new strategy for handling temp files.
|
|
||||||
*/
|
|
||||||
public void setTempFileManagerFactory(TempFileManagerFactory tempFileManagerFactory)
|
|
||||||
{
|
|
||||||
this.tempFileManagerFactory = tempFileManagerFactory;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Factory to create temp file managers.
|
|
||||||
*/
|
|
||||||
public interface TempFileManagerFactory
|
|
||||||
{
|
|
||||||
TempFileManager create();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Temp file manager.
|
|
||||||
*
|
|
||||||
* <p>Temp file managers are created 1-to-1 with incoming requests, to create and cleanup
|
|
||||||
* temporary files created as a result of handling the request.</p>
|
|
||||||
*/
|
|
||||||
public interface TempFileManager
|
|
||||||
{
|
|
||||||
TempFile createTempFile() throws Exception;
|
|
||||||
|
|
||||||
void clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A temp file.
|
|
||||||
*
|
|
||||||
* <p>Temp files are responsible for managing the actual temporary storage and cleaning
|
|
||||||
* themselves up when no longer needed.</p>
|
|
||||||
*/
|
|
||||||
public interface TempFile
|
|
||||||
{
|
|
||||||
OutputStream open() throws Exception;
|
|
||||||
|
|
||||||
void delete() throws Exception;
|
|
||||||
|
|
||||||
String getName();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default strategy for creating and cleaning up temporary files.
|
* Default strategy for creating and cleaning up temporary files.
|
||||||
*/
|
* <p/>
|
||||||
private class DefaultTempFileManagerFactory implements TempFileManagerFactory
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public TempFileManager create()
|
|
||||||
{
|
|
||||||
return new DefaultTempFileManager();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Default strategy for creating and cleaning up temporary files.
|
|
||||||
*
|
|
||||||
* <p></p>This class stores its files in the standard location (that is,
|
* <p></p>This class stores its files in the standard location (that is,
|
||||||
* wherever <code>java.io.tmpdir</code> points to). Files are added
|
* wherever <code>java.io.tmpdir</code> points to). Files are added
|
||||||
* to an internal list, and deleted when no longer needed (that is,
|
* to an internal list, and deleted when no longer needed (that is,
|
||||||
@ -481,7 +525,7 @@ public abstract class NanoHTTPD
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Default strategy for creating and cleaning up temporary files.
|
* Default strategy for creating and cleaning up temporary files.
|
||||||
*
|
* <p/>
|
||||||
* <p></p></[>By default, files are created by <code>File.createTempFile()</code> in
|
* <p></p></[>By default, files are created by <code>File.createTempFile()</code> in
|
||||||
* the directory specified.</p>
|
* the directory specified.</p>
|
||||||
*/
|
*/
|
||||||
@ -516,7 +560,6 @@ public abstract class NanoHTTPD
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------------- //
|
|
||||||
/**
|
/**
|
||||||
* HTTP response. Return one of these from serve().
|
* HTTP response. Return one of these from serve().
|
||||||
*/
|
*/
|
||||||
@ -542,6 +585,10 @@ public abstract class NanoHTTPD
|
|||||||
* The request method that spawned this response.
|
* The request method that spawned this response.
|
||||||
*/
|
*/
|
||||||
private Method requestMethod;
|
private Method requestMethod;
|
||||||
|
/**
|
||||||
|
* Use chunkedTransfer
|
||||||
|
*/
|
||||||
|
private boolean chunkedTransfer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default constructor: response = HTTP_OK, mime = MIME_HTML and your supplied message
|
* Default constructor: response = HTTP_OK, mime = MIME_HTML and your supplied message
|
||||||
@ -623,31 +670,15 @@ public abstract class NanoHTTPD
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int pending = data != null ? data.available() : -1; // This is to support partial sends, see serveFile()
|
pw.print("Connection: keep-alive\r\n");
|
||||||
if (pending > 0)
|
|
||||||
|
if (requestMethod != Method.HEAD && chunkedTransfer)
|
||||||
{
|
{
|
||||||
pw.print("Connection: keep-alive\r\n");
|
sendAsChunked(outputStream, pw);
|
||||||
pw.print("Content-Length: " + pending + "\r\n");
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
pw.print("\r\n");
|
|
||||||
pw.flush();
|
|
||||||
|
|
||||||
if (requestMethod != Method.HEAD && data != null)
|
|
||||||
{
|
{
|
||||||
int BUFFER_SIZE = 16 * 1024;
|
sendAsFixedLength(outputStream, pw);
|
||||||
byte[] buff = new byte[BUFFER_SIZE];
|
|
||||||
while (pending > 0)
|
|
||||||
{
|
|
||||||
int read = data.read(buff, 0, ((pending > BUFFER_SIZE) ? BUFFER_SIZE : pending));
|
|
||||||
if (read <= 0)
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
outputStream.write(buff, 0, read);
|
|
||||||
|
|
||||||
pending -= read;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
outputStream.flush();
|
outputStream.flush();
|
||||||
safeClose(data);
|
safeClose(data);
|
||||||
@ -658,6 +689,50 @@ public abstract class NanoHTTPD
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void sendAsChunked(OutputStream outputStream, PrintWriter pw) throws IOException
|
||||||
|
{
|
||||||
|
pw.print("Transfer-Encoding: chunked\r\n");
|
||||||
|
pw.print("\r\n");
|
||||||
|
pw.flush();
|
||||||
|
int BUFFER_SIZE = 16 * 1024;
|
||||||
|
byte[] CRLF = "\r\n".getBytes();
|
||||||
|
byte[] buff = new byte[BUFFER_SIZE];
|
||||||
|
int read;
|
||||||
|
while ((read = data.read(buff)) > 0)
|
||||||
|
{
|
||||||
|
outputStream.write(String.format("%x\r\n", read).getBytes());
|
||||||
|
outputStream.write(buff, 0, read);
|
||||||
|
outputStream.write(CRLF);
|
||||||
|
}
|
||||||
|
outputStream.write(String.format("0\r\n\r\n").getBytes());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendAsFixedLength(OutputStream outputStream, PrintWriter pw) throws IOException
|
||||||
|
{
|
||||||
|
int pending = data != null ? data.available() : 0; // This is to support partial sends, see serveFile()
|
||||||
|
pw.print("Content-Length: " + pending + "\r\n");
|
||||||
|
|
||||||
|
pw.print("\r\n");
|
||||||
|
pw.flush();
|
||||||
|
|
||||||
|
if (requestMethod != Method.HEAD && data != null)
|
||||||
|
{
|
||||||
|
int BUFFER_SIZE = 16 * 1024;
|
||||||
|
byte[] buff = new byte[BUFFER_SIZE];
|
||||||
|
while (pending > 0)
|
||||||
|
{
|
||||||
|
int read = data.read(buff, 0, ((pending > BUFFER_SIZE) ? BUFFER_SIZE : pending));
|
||||||
|
if (read <= 0)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
outputStream.write(buff, 0, read);
|
||||||
|
|
||||||
|
pending -= read;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public Status getStatus()
|
public Status getStatus()
|
||||||
{
|
{
|
||||||
return status;
|
return status;
|
||||||
@ -698,6 +773,11 @@ public abstract class NanoHTTPD
|
|||||||
this.requestMethod = requestMethod;
|
this.requestMethod = requestMethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setChunkedTransfer(boolean chunkedTransfer)
|
||||||
|
{
|
||||||
|
this.chunkedTransfer = chunkedTransfer;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Some HTTP response status codes
|
* Some HTTP response status codes
|
||||||
*/
|
*/
|
||||||
@ -728,6 +808,40 @@ public abstract class NanoHTTPD
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static final class ResponseException extends Exception
|
||||||
|
{
|
||||||
|
private final Response.Status status;
|
||||||
|
|
||||||
|
public ResponseException(Response.Status status, String message)
|
||||||
|
{
|
||||||
|
super(message);
|
||||||
|
this.status = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResponseException(Response.Status status, String message, Exception e)
|
||||||
|
{
|
||||||
|
super(message, e);
|
||||||
|
this.status = status;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Response.Status getStatus()
|
||||||
|
{
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default strategy for creating and cleaning up temporary files.
|
||||||
|
*/
|
||||||
|
private class DefaultTempFileManagerFactory implements TempFileManagerFactory
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public TempFileManager create()
|
||||||
|
{
|
||||||
|
return new DefaultTempFileManager();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles one session, i.e. parses the HTTP request and returns the response.
|
* Handles one session, i.e. parses the HTTP request and returns the response.
|
||||||
*/
|
*/
|
||||||
@ -735,17 +849,18 @@ public abstract class NanoHTTPD
|
|||||||
{
|
{
|
||||||
public static final int BUFSIZE = 8192;
|
public static final int BUFSIZE = 8192;
|
||||||
private final TempFileManager tempFileManager;
|
private final TempFileManager tempFileManager;
|
||||||
private InputStream inputStream;
|
|
||||||
private final OutputStream outputStream;
|
private final OutputStream outputStream;
|
||||||
|
private final Socket socket;
|
||||||
|
private InputStream inputStream;
|
||||||
private int splitbyte;
|
private int splitbyte;
|
||||||
private int rlen;
|
private int rlen;
|
||||||
private String uri;
|
private String uri;
|
||||||
private Method method;
|
private Method method;
|
||||||
private Map<String, String> parms;
|
private Map<String, String> parms;
|
||||||
private Map<String, String> headers;
|
private Map<String, String> headers;
|
||||||
private Socket socket;
|
private CookieHandler cookies;
|
||||||
|
|
||||||
private HTTPSession(TempFileManager tempFileManager, InputStream inputStream, OutputStream outputStream, Socket socket)
|
public HTTPSession(TempFileManager tempFileManager, InputStream inputStream, OutputStream outputStream, Socket socket)
|
||||||
{
|
{
|
||||||
this.tempFileManager = tempFileManager;
|
this.tempFileManager = tempFileManager;
|
||||||
this.inputStream = inputStream;
|
this.inputStream = inputStream;
|
||||||
@ -808,6 +923,8 @@ public abstract class NanoHTTPD
|
|||||||
|
|
||||||
uri = pre.get("uri");
|
uri = pre.get("uri");
|
||||||
|
|
||||||
|
cookies = new CookieHandler(headers);
|
||||||
|
|
||||||
// Ok, now do the serve()
|
// Ok, now do the serve()
|
||||||
Response r = serve(this);
|
Response r = serve(this);
|
||||||
if (r == null)
|
if (r == null)
|
||||||
@ -816,6 +933,7 @@ public abstract class NanoHTTPD
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
cookies.unloadQueue(r);
|
||||||
r.setRequestMethod(method);
|
r.setRequestMethod(method);
|
||||||
r.send(outputStream);
|
r.send(outputStream);
|
||||||
}
|
}
|
||||||
@ -843,7 +961,7 @@ public abstract class NanoHTTPD
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void parseBody(Map<String, String> files) throws IOException, ResponseException
|
protected void parseBody(Map<String, String> files) throws IOException, ResponseException
|
||||||
{
|
{
|
||||||
RandomAccessFile randomAccessFile = null;
|
RandomAccessFile randomAccessFile = null;
|
||||||
BufferedReader in = null;
|
BufferedReader in = null;
|
||||||
@ -914,7 +1032,7 @@ public abstract class NanoHTTPD
|
|||||||
String boundaryStartString = "boundary=";
|
String boundaryStartString = "boundary=";
|
||||||
int boundaryContentStart = contentTypeHeader.indexOf(boundaryStartString) + boundaryStartString.length();
|
int boundaryContentStart = contentTypeHeader.indexOf(boundaryStartString) + boundaryStartString.length();
|
||||||
String boundary = contentTypeHeader.substring(boundaryContentStart, contentTypeHeader.length());
|
String boundary = contentTypeHeader.substring(boundaryContentStart, contentTypeHeader.length());
|
||||||
if (boundary.startsWith("\"") && boundary.startsWith("\""))
|
if (boundary.startsWith("\"") && boundary.endsWith("\""))
|
||||||
{
|
{
|
||||||
boundary = boundary.substring(1, boundary.length() - 1);
|
boundary = boundary.substring(1, boundary.length() - 1);
|
||||||
}
|
}
|
||||||
@ -1189,7 +1307,7 @@ public abstract class NanoHTTPD
|
|||||||
path = tempFile.getName();
|
path = tempFile.getName();
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{ // Catch exception if any
|
||||||
TFM_Log.severe(e);
|
TFM_Log.severe(e);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
@ -1285,88 +1403,140 @@ public abstract class NanoHTTPD
|
|||||||
return inputStream;
|
return inputStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
public final Socket getSocket()
|
public CookieHandler getCookies()
|
||||||
|
{
|
||||||
|
return cookies;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Socket getSocket()
|
||||||
{
|
{
|
||||||
return socket;
|
return socket;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class ResponseException extends Exception
|
public static class Cookie
|
||||||
{
|
{
|
||||||
private final Response.Status status;
|
private String n, v, e;
|
||||||
|
|
||||||
public ResponseException(Response.Status status, String message)
|
public Cookie(String name, String value, String expires)
|
||||||
{
|
{
|
||||||
super(message);
|
n = name;
|
||||||
this.status = status;
|
v = value;
|
||||||
|
e = expires;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ResponseException(Response.Status status, String message, Exception e)
|
public Cookie(String name, String value)
|
||||||
{
|
{
|
||||||
super(message, e);
|
this(name, value, 30);
|
||||||
this.status = status;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Response.Status getStatus()
|
public Cookie(String name, String value, int numDays)
|
||||||
{
|
{
|
||||||
return status;
|
n = name;
|
||||||
|
v = value;
|
||||||
|
e = getHTTPTime(numDays);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getHTTPHeader()
|
||||||
|
{
|
||||||
|
String fmt = "%s=%s; expires=%s";
|
||||||
|
return String.format(fmt, n, v, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getHTTPTime(int days)
|
||||||
|
{
|
||||||
|
Calendar calendar = Calendar.getInstance();
|
||||||
|
SimpleDateFormat dateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
|
||||||
|
dateFormat.setTimeZone(TimeZone.getTimeZone("GMT"));
|
||||||
|
calendar.add(Calendar.DAY_OF_MONTH, days);
|
||||||
|
return dateFormat.format(calendar.getTime());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final void safeClose(ServerSocket serverSocket)
|
/**
|
||||||
|
* Provides rudimentary support for cookies.
|
||||||
|
* Doesn't support 'path', 'secure' nor 'httpOnly'.
|
||||||
|
* Feel free to improve it and/or add unsupported features.
|
||||||
|
*
|
||||||
|
* @author LordFokas
|
||||||
|
*/
|
||||||
|
public class CookieHandler implements Iterable<String>
|
||||||
{
|
{
|
||||||
if (serverSocket != null)
|
private HashMap<String, String> cookies = new HashMap<String, String>();
|
||||||
|
private ArrayList<Cookie> queue = new ArrayList<Cookie>();
|
||||||
|
|
||||||
|
public CookieHandler(Map<String, String> httpHeaders)
|
||||||
{
|
{
|
||||||
try
|
String raw = httpHeaders.get("cookie");
|
||||||
|
if (raw != null)
|
||||||
{
|
{
|
||||||
serverSocket.close();
|
String[] tokens = raw.split(";");
|
||||||
|
for (String token : tokens)
|
||||||
|
{
|
||||||
|
String[] data = token.trim().split("=");
|
||||||
|
if (data.length == 2)
|
||||||
|
{
|
||||||
|
cookies.put(data[0], data[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (IOException e)
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iterator<String> iterator()
|
||||||
|
{
|
||||||
|
return cookies.keySet().iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read a cookie from the HTTP Headers.
|
||||||
|
*
|
||||||
|
* @param name The cookie's name.
|
||||||
|
* @return The cookie's value if it exists, null otherwise.
|
||||||
|
*/
|
||||||
|
public String read(String name)
|
||||||
|
{
|
||||||
|
return cookies.get(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a cookie.
|
||||||
|
*
|
||||||
|
* @param name The cookie's name.
|
||||||
|
* @param value The cookie's value.
|
||||||
|
* @param expires How many days until the cookie expires.
|
||||||
|
*/
|
||||||
|
public void set(String name, String value, int expires)
|
||||||
|
{
|
||||||
|
queue.add(new Cookie(name, value, Cookie.getHTTPTime(expires)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void set(Cookie cookie)
|
||||||
|
{
|
||||||
|
queue.add(cookie);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a cookie with an expiration date from a month ago, effectively deleting it on the client side.
|
||||||
|
*
|
||||||
|
* @param name The cookie name.
|
||||||
|
*/
|
||||||
|
public void delete(String name)
|
||||||
|
{
|
||||||
|
set(name, "-delete-", -30);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internally used by the webserver to add all queued cookies into the Response's HTTP Headers.
|
||||||
|
*
|
||||||
|
* @param response The Response object to which headers the queued cookies will be added.
|
||||||
|
*/
|
||||||
|
public void unloadQueue(Response response)
|
||||||
|
{
|
||||||
|
for (Cookie cookie : queue)
|
||||||
{
|
{
|
||||||
|
response.addHeader("Set-Cookie", cookie.getHTTPHeader());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
private static final void safeClose(Socket socket)
|
|
||||||
{
|
|
||||||
if (socket != null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
socket.close();
|
|
||||||
}
|
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final void safeClose(Closeable closeable)
|
|
||||||
{
|
|
||||||
if (closeable != null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
closeable.close();
|
|
||||||
}
|
|
||||||
catch (IOException e)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public final int getListeningPort()
|
|
||||||
{
|
|
||||||
return myServerSocket == null ? -1 : myServerSocket.getLocalPort();
|
|
||||||
}
|
|
||||||
|
|
||||||
public final boolean wasStarted()
|
|
||||||
{
|
|
||||||
return myServerSocket != null && myThread != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public final boolean isAlive()
|
|
||||||
{
|
|
||||||
return wasStarted() && !myServerSocket.isClosed() && myThread.isAlive();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -3,12 +3,10 @@ package me.StevenLawson.TotalFreedomMod.HTTPD;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.Socket;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
import java.util.concurrent.Future;
|
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
import me.StevenLawson.TotalFreedomMod.HTTPD.NanoHTTPD.HTTPSession;
|
||||||
import me.StevenLawson.TotalFreedomMod.HTTPD.NanoHTTPD.Response;
|
import me.StevenLawson.TotalFreedomMod.HTTPD.NanoHTTPD.Response;
|
||||||
import me.StevenLawson.TotalFreedomMod.TFM_ConfigEntry;
|
import me.StevenLawson.TotalFreedomMod.TFM_ConfigEntry;
|
||||||
import me.StevenLawson.TotalFreedomMod.TFM_Log;
|
import me.StevenLawson.TotalFreedomMod.TFM_Log;
|
||||||
@ -19,6 +17,9 @@ import org.bukkit.Bukkit;
|
|||||||
|
|
||||||
public class TFM_HTTPD_Manager
|
public class TFM_HTTPD_Manager
|
||||||
{
|
{
|
||||||
|
@Deprecated
|
||||||
|
public static String MIME_DEFAULT_BINARY = "application/octet-stream";
|
||||||
|
//
|
||||||
private static final Pattern EXT_REGEX = Pattern.compile("\\.([^\\.\\s]+)$");
|
private static final Pattern EXT_REGEX = Pattern.compile("\\.([^\\.\\s]+)$");
|
||||||
//
|
//
|
||||||
public static final int PORT = TFM_ConfigEntry.HTTPD_PORT.getInteger();
|
public static final int PORT = TFM_ConfigEntry.HTTPD_PORT.getInteger();
|
||||||
@ -69,36 +70,118 @@ public class TFM_HTTPD_Manager
|
|||||||
|
|
||||||
private static enum ModuleType
|
private static enum ModuleType
|
||||||
{
|
{
|
||||||
DUMP(false, "dump"),
|
DUMP(new ModuleExecutable(false, "dump")
|
||||||
HELP(true, "help"),
|
|
||||||
LIST(true, "list"),
|
|
||||||
FILE(false, "file"),
|
|
||||||
SCHEMATIC(false, "schematic"),
|
|
||||||
PERMBANS(false, "permbans");
|
|
||||||
private final boolean runOnBukkitThread;
|
|
||||||
private final String name;
|
|
||||||
|
|
||||||
private ModuleType(boolean runOnBukkitThread, String name)
|
|
||||||
{
|
{
|
||||||
this.runOnBukkitThread = runOnBukkitThread;
|
@Override
|
||||||
this.name = name;
|
public Response getResponse(HTTPSession session)
|
||||||
|
{
|
||||||
|
return new Response(Response.Status.OK, NanoHTTPD.MIME_PLAINTEXT, "The DUMP module is disabled. It is intended for debugging use only.");
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
HELP(new ModuleExecutable(true, "help")
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public Response getResponse(HTTPSession session)
|
||||||
|
{
|
||||||
|
return new Module_help(session).getResponse();
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
LIST(new ModuleExecutable(true, "list")
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public Response getResponse(HTTPSession session)
|
||||||
|
{
|
||||||
|
return new Module_list(session).getResponse();
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
FILE(new ModuleExecutable(false, "file")
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public Response getResponse(HTTPSession session)
|
||||||
|
{
|
||||||
|
return new Module_file(session).getResponse();
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
SCHEMATIC(new ModuleExecutable(false, "schematic")
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public Response getResponse(HTTPSession session)
|
||||||
|
{
|
||||||
|
return new Module_schematic(session).getResponse();
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
PERMBANS(new ModuleExecutable(false, "permbans")
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public Response getResponse(HTTPSession session)
|
||||||
|
{
|
||||||
|
return new Module_permbans(session).getResponse();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
//
|
||||||
|
private final ModuleExecutable moduleExecutable;
|
||||||
|
|
||||||
|
private ModuleType(ModuleExecutable moduleExecutable)
|
||||||
|
{
|
||||||
|
this.moduleExecutable = moduleExecutable;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isRunOnBukkitThread()
|
private abstract static class ModuleExecutable
|
||||||
{
|
{
|
||||||
return runOnBukkitThread;
|
private final boolean runOnBukkitThread;
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
public ModuleExecutable(boolean runOnBukkitThread, String name)
|
||||||
|
{
|
||||||
|
this.runOnBukkitThread = runOnBukkitThread;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Response execute(final HTTPSession session)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (this.runOnBukkitThread)
|
||||||
|
{
|
||||||
|
return Bukkit.getScheduler().callSyncMethod(TotalFreedomMod.plugin, new Callable<Response>()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public Response call() throws Exception
|
||||||
|
{
|
||||||
|
return getResponse(session);
|
||||||
|
}
|
||||||
|
}).get();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return getResponse(session);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
TFM_Log.severe(ex);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract Response getResponse(HTTPSession session);
|
||||||
|
|
||||||
|
public String getName()
|
||||||
|
{
|
||||||
|
return name;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getName()
|
public ModuleExecutable getModuleExecutable()
|
||||||
{
|
{
|
||||||
return name;
|
return moduleExecutable;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ModuleType getByName(String needle)
|
private static ModuleType getByName(String needle)
|
||||||
{
|
{
|
||||||
for (ModuleType type : values())
|
for (ModuleType type : values())
|
||||||
{
|
{
|
||||||
if (type.getName().equalsIgnoreCase(needle))
|
if (type.getModuleExecutable().getName().equalsIgnoreCase(needle))
|
||||||
{
|
{
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
@ -120,68 +203,15 @@ public class TFM_HTTPD_Manager
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Response serve(
|
public Response serve(HTTPSession session)
|
||||||
final String uri,
|
|
||||||
final Method method,
|
|
||||||
final Map<String, String> headers,
|
|
||||||
final Map<String, String> params,
|
|
||||||
final Map<String, String> files,
|
|
||||||
final Socket socket)
|
|
||||||
{
|
{
|
||||||
Response response = null;
|
Response response;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
final String[] args = StringUtils.split(session.getUri(), "/");
|
||||||
final String[] args = StringUtils.split(uri, "/");
|
|
||||||
final ModuleType moduleType = args.length >= 1 ? ModuleType.getByName(args[0]) : ModuleType.FILE;
|
final ModuleType moduleType = args.length >= 1 ? ModuleType.getByName(args[0]) : ModuleType.FILE;
|
||||||
|
response = moduleType.getModuleExecutable().execute(session);
|
||||||
if (moduleType.isRunOnBukkitThread())
|
|
||||||
{
|
|
||||||
Future<Response> responseCall = Bukkit.getScheduler().callSyncMethod(TotalFreedomMod.plugin, new Callable<Response>()
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public Response call() throws Exception
|
|
||||||
{
|
|
||||||
switch (moduleType)
|
|
||||||
{
|
|
||||||
case HELP:
|
|
||||||
return new Module_help(uri, method, headers, params, files, socket).getResponse();
|
|
||||||
case LIST:
|
|
||||||
return new Module_list(uri, method, headers, params, files, socket).getResponse();
|
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
response = responseCall.get();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
TFM_Log.severe(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
switch (moduleType)
|
|
||||||
{
|
|
||||||
case DUMP:
|
|
||||||
//response = new Module_dump(uri, method, headers, params, files, socket).getResponse();
|
|
||||||
response = new Response(Response.Status.OK, MIME_PLAINTEXT, "The DUMP module is disabled. It is intended for debugging use only.");
|
|
||||||
break;
|
|
||||||
case SCHEMATIC:
|
|
||||||
response = new Module_schematic(uri, method, headers, params, files, socket).getResponse();
|
|
||||||
break;
|
|
||||||
case PERMBANS:
|
|
||||||
response = new Module_permbans(uri, method, headers, params, files, socket).getResponse();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
response = new Module_file(uri, method, headers, params, files, socket).getResponse();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@ -215,10 +245,10 @@ public class TFM_HTTPD_Manager
|
|||||||
|
|
||||||
if (mimetype == null || mimetype.trim().isEmpty())
|
if (mimetype == null || mimetype.trim().isEmpty())
|
||||||
{
|
{
|
||||||
mimetype = NanoHTTPD.MIME_DEFAULT_BINARY;
|
mimetype = MIME_DEFAULT_BINARY;
|
||||||
}
|
}
|
||||||
|
|
||||||
response = new NanoHTTPD.Response(NanoHTTPD.Response.Status.OK, mimetype, new FileInputStream(file));
|
response = new Response(Response.Status.OK, mimetype, new FileInputStream(file));
|
||||||
response.addHeader("Content-Length", "" + file.length());
|
response.addHeader("Content-Length", "" + file.length());
|
||||||
}
|
}
|
||||||
catch (IOException ex)
|
catch (IOException ex)
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
package me.StevenLawson.TotalFreedomMod.HTTPD;
|
package me.StevenLawson.TotalFreedomMod.HTTPD;
|
||||||
|
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import me.StevenLawson.TotalFreedomMod.HTTPD.NanoHTTPD.*;
|
import me.StevenLawson.TotalFreedomMod.HTTPD.NanoHTTPD.*;
|
||||||
|
import me.StevenLawson.TotalFreedomMod.TFM_Log;
|
||||||
|
|
||||||
public abstract class TFM_HTTPD_Module
|
public abstract class TFM_HTTPD_Module
|
||||||
{
|
{
|
||||||
@ -10,17 +12,17 @@ public abstract class TFM_HTTPD_Module
|
|||||||
protected final Method method;
|
protected final Method method;
|
||||||
protected final Map<String, String> headers;
|
protected final Map<String, String> headers;
|
||||||
protected final Map<String, String> params;
|
protected final Map<String, String> params;
|
||||||
protected final Map<String, String> files;
|
|
||||||
protected final Socket socket;
|
protected final Socket socket;
|
||||||
|
protected final HTTPSession session;
|
||||||
|
|
||||||
public TFM_HTTPD_Module(String uri, Method method, Map<String, String> headers, Map<String, String> params, Map<String, String> files, Socket socket)
|
public TFM_HTTPD_Module(HTTPSession session)
|
||||||
{
|
{
|
||||||
this.uri = uri;
|
this.uri = session.getUri();
|
||||||
this.method = method;
|
this.method = session.getMethod();
|
||||||
this.headers = headers;
|
this.headers = session.getHeaders();
|
||||||
this.params = params;
|
this.params = session.getParms();
|
||||||
this.files = files;
|
this.socket = session.getSocket();
|
||||||
this.socket = socket;
|
this.session = session;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getBody()
|
public String getBody()
|
||||||
@ -47,4 +49,20 @@ public abstract class TFM_HTTPD_Module
|
|||||||
{
|
{
|
||||||
return new TFM_HTTPD_PageBuilder(getBody(), getTitle(), getStyle(), getScript()).getResponse();
|
return new TFM_HTTPD_PageBuilder(getBody(), getTitle(), getStyle(), getScript()).getResponse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected final Map<String, String> getFiles()
|
||||||
|
{
|
||||||
|
Map<String, String> files = new HashMap<String, String>();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
session.parseBody(files);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
TFM_Log.severe(ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return files;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user