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.BUILDNUM=595
|
||||
program.BUILDDATE=09/17/2013 12\:03 PM
|
||||
program.BUILDNUM=596
|
||||
program.BUILDDATE=09/17/2013 09\:28 PM
|
||||
|
@ -1,3 +1,3 @@
|
||||
#Build Number for ANT. Do not edit!
|
||||
#Tue Sep 17 12:03:45 EDT 2013
|
||||
build.number=596
|
||||
#Tue Sep 17 21:28:11 EDT 2013
|
||||
build.number=597
|
||||
|
@ -2,7 +2,6 @@ package me.StevenLawson.TotalFreedomMod.HTTPD;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.Socket;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
@ -16,9 +15,9 @@ public class Module_dump extends TFM_HTTPD_Module
|
||||
private File echoFile = null;
|
||||
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.
|
||||
this.body = body();
|
||||
@ -54,6 +53,8 @@ public class Module_dump extends TFM_HTTPD_Module
|
||||
|
||||
String[] args = StringUtils.split(uri, "/");
|
||||
|
||||
Map<String, String> files = getFiles();
|
||||
|
||||
responseBody
|
||||
.append(paragraph("URI: " + uri))
|
||||
.append(paragraph("args (Length: " + args.length + "): " + StringUtils.join(args, ",")))
|
||||
|
@ -5,7 +5,6 @@ import java.io.FileInputStream;
|
||||
import java.io.FilenameFilter;
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.Socket;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
@ -13,9 +12,9 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.StringTokenizer;
|
||||
import me.StevenLawson.TotalFreedomMod.TFM_ConfigEntry;
|
||||
|
||||
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
|
||||
@ -55,9 +54,9 @@ public class Module_file extends TFM_HTTPD_Module
|
||||
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()
|
||||
@ -175,7 +174,7 @@ public class Module_file extends TFM_HTTPD_Module
|
||||
}
|
||||
if (mime == null)
|
||||
{
|
||||
mime = NanoHTTPD.MIME_DEFAULT_BINARY;
|
||||
mime = TFM_HTTPD_Manager.MIME_DEFAULT_BINARY;
|
||||
}
|
||||
|
||||
// Calculate etag
|
||||
|
@ -1,6 +1,5 @@
|
||||
package me.StevenLawson.TotalFreedomMod.HTTPD;
|
||||
|
||||
import java.net.Socket;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
@ -21,9 +20,9 @@ import static org.apache.commons.lang3.StringEscapeUtils.*;
|
||||
|
||||
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
|
||||
|
@ -1,7 +1,5 @@
|
||||
package me.StevenLawson.TotalFreedomMod.HTTPD;
|
||||
|
||||
import java.net.Socket;
|
||||
import java.util.Map;
|
||||
import me.StevenLawson.TotalFreedomMod.TFM_SuperadminList;
|
||||
import me.StevenLawson.TotalFreedomMod.TFM_Util;
|
||||
import org.bukkit.Bukkit;
|
||||
@ -9,9 +7,9 @@ import org.bukkit.entity.Player;
|
||||
|
||||
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
|
||||
|
@ -1,15 +1,13 @@
|
||||
package me.StevenLawson.TotalFreedomMod.HTTPD;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.Socket;
|
||||
import java.util.Map;
|
||||
import me.StevenLawson.TotalFreedomMod.TotalFreedomMod;
|
||||
|
||||
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
|
||||
|
@ -2,7 +2,6 @@ package me.StevenLawson.TotalFreedomMod.HTTPD;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.Socket;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
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_SuperadminList;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.StringEscapeUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
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"
|
||||
+ "</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
|
||||
@ -153,6 +152,8 @@ public class Module_schematic extends TFM_HTTPD_Module
|
||||
|
||||
private boolean uploadSchematic() throws SchematicTransferException
|
||||
{
|
||||
Map<String, String> files = getFiles();
|
||||
|
||||
final String tempFileName = files.get(REQUEST_FORM_FILE_ELEMENT_NAME);
|
||||
if (tempFileName == null)
|
||||
{
|
||||
|
@ -1,11 +1,7 @@
|
||||
package me.StevenLawson.TotalFreedomMod.HTTPD;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketException;
|
||||
import java.net.URLDecoder;
|
||||
import java.net.*;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.text.SimpleDateFormat;
|
||||
@ -67,17 +63,21 @@ public abstract class NanoHTTPD
|
||||
*/
|
||||
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 int myPort;
|
||||
private ServerSocket myServerSocket;
|
||||
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.
|
||||
@ -98,8 +98,51 @@ public abstract class NanoHTTPD
|
||||
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.
|
||||
*
|
||||
* @throws IOException if the socket is in use.
|
||||
*/
|
||||
public void start() throws IOException
|
||||
@ -187,6 +230,21 @@ 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.
|
||||
* <p/>
|
||||
@ -199,8 +257,12 @@ public abstract class NanoHTTPD
|
||||
* @param headers Header entries, percent decoded
|
||||
* @return HTTP response, see class Response for details
|
||||
*/
|
||||
public abstract Response serve(String uri, Method method, Map<String, String> headers, Map<String, String> parms,
|
||||
Map<String, String> files, Socket socket);
|
||||
@Deprecated
|
||||
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.
|
||||
@ -211,10 +273,12 @@ public abstract class NanoHTTPD
|
||||
* @param session The HTTP session
|
||||
* @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>();
|
||||
|
||||
Method method = session.getMethod();
|
||||
if (Method.PUT.equals(method) || Method.POST.equals(method))
|
||||
{
|
||||
try
|
||||
{
|
||||
session.parseBody(files);
|
||||
@ -227,17 +291,14 @@ public abstract class NanoHTTPD
|
||||
{
|
||||
return new Response(re.getStatus(), MIME_PLAINTEXT, re.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
String uri = session.getUri();
|
||||
Method method = session.getMethod();
|
||||
Map<String, String> parms = session.getParms();
|
||||
Map<String, String> headers = session.getHeaders();
|
||||
Socket socket = session.getSocket();
|
||||
return serve(uri, method, headers, parms, files, socket);
|
||||
return serve(session.getUri(), method, session.getHeaders(), session.getParms(), files);
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode percent encoded <code>String</code> values.
|
||||
*
|
||||
* @param str the percent encoded <code>String</code>
|
||||
* @return expanded form of the input, for example "foo%20bar" becomes "foo bar"
|
||||
*/
|
||||
@ -300,6 +361,36 @@ public abstract class NanoHTTPD
|
||||
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.
|
||||
*/
|
||||
@ -319,24 +410,6 @@ public abstract class NanoHTTPD
|
||||
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.
|
||||
@ -346,9 +419,46 @@ public abstract class NanoHTTPD
|
||||
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.
|
||||
*
|
||||
* <p/>
|
||||
* <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
|
||||
* useful when profiling the application.</p>
|
||||
@ -367,76 +477,10 @@ public abstract class NanoHTTPD
|
||||
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.
|
||||
*/
|
||||
private class DefaultTempFileManagerFactory implements TempFileManagerFactory
|
||||
{
|
||||
@Override
|
||||
public TempFileManager create()
|
||||
{
|
||||
return new DefaultTempFileManager();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Default strategy for creating and cleaning up temporary files.
|
||||
*
|
||||
* <p/>
|
||||
* <p></p>This class stores its files in the standard location (that is,
|
||||
* wherever <code>java.io.tmpdir</code> points to). Files are added
|
||||
* 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.
|
||||
*
|
||||
* <p/>
|
||||
* <p></p></[>By default, files are created by <code>File.createTempFile()</code> in
|
||||
* the directory specified.</p>
|
||||
*/
|
||||
@ -516,7 +560,6 @@ public abstract class NanoHTTPD
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------- //
|
||||
/**
|
||||
* HTTP response. Return one of these from serve().
|
||||
*/
|
||||
@ -542,6 +585,10 @@ public abstract class NanoHTTPD
|
||||
* The request method that spawned this response.
|
||||
*/
|
||||
private Method requestMethod;
|
||||
/**
|
||||
* Use chunkedTransfer
|
||||
*/
|
||||
private boolean chunkedTransfer;
|
||||
|
||||
/**
|
||||
* Default constructor: response = HTTP_OK, mime = MIME_HTML and your supplied message
|
||||
@ -623,12 +670,47 @@ public abstract class NanoHTTPD
|
||||
}
|
||||
}
|
||||
|
||||
int pending = data != null ? data.available() : -1; // This is to support partial sends, see serveFile()
|
||||
if (pending > 0)
|
||||
{
|
||||
pw.print("Connection: keep-alive\r\n");
|
||||
pw.print("Content-Length: " + pending + "\r\n");
|
||||
|
||||
if (requestMethod != Method.HEAD && chunkedTransfer)
|
||||
{
|
||||
sendAsChunked(outputStream, pw);
|
||||
}
|
||||
else
|
||||
{
|
||||
sendAsFixedLength(outputStream, pw);
|
||||
}
|
||||
outputStream.flush();
|
||||
safeClose(data);
|
||||
}
|
||||
catch (IOException ioe)
|
||||
{
|
||||
// Couldn't write? No can do.
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
@ -649,13 +731,6 @@ public abstract class NanoHTTPD
|
||||
pending -= read;
|
||||
}
|
||||
}
|
||||
outputStream.flush();
|
||||
safeClose(data);
|
||||
}
|
||||
catch (IOException ioe)
|
||||
{
|
||||
// Couldn't write? No can do.
|
||||
}
|
||||
}
|
||||
|
||||
public Status getStatus()
|
||||
@ -698,6 +773,11 @@ public abstract class NanoHTTPD
|
||||
this.requestMethod = requestMethod;
|
||||
}
|
||||
|
||||
public void setChunkedTransfer(boolean chunkedTransfer)
|
||||
{
|
||||
this.chunkedTransfer = chunkedTransfer;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
@ -735,17 +849,18 @@ public abstract class NanoHTTPD
|
||||
{
|
||||
public static final int BUFSIZE = 8192;
|
||||
private final TempFileManager tempFileManager;
|
||||
private InputStream inputStream;
|
||||
private final OutputStream outputStream;
|
||||
private final Socket socket;
|
||||
private InputStream inputStream;
|
||||
private int splitbyte;
|
||||
private int rlen;
|
||||
private String uri;
|
||||
private Method method;
|
||||
private Map<String, String> parms;
|
||||
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.inputStream = inputStream;
|
||||
@ -808,6 +923,8 @@ public abstract class NanoHTTPD
|
||||
|
||||
uri = pre.get("uri");
|
||||
|
||||
cookies = new CookieHandler(headers);
|
||||
|
||||
// Ok, now do the serve()
|
||||
Response r = serve(this);
|
||||
if (r == null)
|
||||
@ -816,6 +933,7 @@ public abstract class NanoHTTPD
|
||||
}
|
||||
else
|
||||
{
|
||||
cookies.unloadQueue(r);
|
||||
r.setRequestMethod(method);
|
||||
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;
|
||||
BufferedReader in = null;
|
||||
@ -914,7 +1032,7 @@ public abstract class NanoHTTPD
|
||||
String boundaryStartString = "boundary=";
|
||||
int boundaryContentStart = contentTypeHeader.indexOf(boundaryStartString) + boundaryStartString.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);
|
||||
}
|
||||
@ -1189,7 +1307,7 @@ public abstract class NanoHTTPD
|
||||
path = tempFile.getName();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
{ // Catch exception if any
|
||||
TFM_Log.severe(e);
|
||||
}
|
||||
finally
|
||||
@ -1285,88 +1403,140 @@ public abstract class NanoHTTPD
|
||||
return inputStream;
|
||||
}
|
||||
|
||||
public final Socket getSocket()
|
||||
public CookieHandler getCookies()
|
||||
{
|
||||
return cookies;
|
||||
}
|
||||
|
||||
public Socket getSocket()
|
||||
{
|
||||
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);
|
||||
this.status = status;
|
||||
n = name;
|
||||
v = value;
|
||||
e = expires;
|
||||
}
|
||||
|
||||
public ResponseException(Response.Status status, String message, Exception e)
|
||||
public Cookie(String name, String value)
|
||||
{
|
||||
super(message, e);
|
||||
this.status = status;
|
||||
this(name, value, 30);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static final void safeClose(Socket socket)
|
||||
@Override
|
||||
public Iterator<String> iterator()
|
||||
{
|
||||
if (socket != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
socket.close();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
}
|
||||
}
|
||||
return cookies.keySet().iterator();
|
||||
}
|
||||
|
||||
private static final void safeClose(Closeable closeable)
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
if (closeable != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
closeable.close();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
}
|
||||
}
|
||||
return cookies.get(name);
|
||||
}
|
||||
|
||||
public final int getListeningPort()
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
return myServerSocket == null ? -1 : myServerSocket.getLocalPort();
|
||||
queue.add(new Cookie(name, value, Cookie.getHTTPTime(expires)));
|
||||
}
|
||||
|
||||
public final boolean wasStarted()
|
||||
public void set(Cookie cookie)
|
||||
{
|
||||
return myServerSocket != null && myThread != null;
|
||||
queue.add(cookie);
|
||||
}
|
||||
|
||||
public final boolean isAlive()
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
return wasStarted() && !myServerSocket.isClosed() && myThread.isAlive();
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -3,12 +3,10 @@ package me.StevenLawson.TotalFreedomMod.HTTPD;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.Socket;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import me.StevenLawson.TotalFreedomMod.HTTPD.NanoHTTPD.HTTPSession;
|
||||
import me.StevenLawson.TotalFreedomMod.HTTPD.NanoHTTPD.Response;
|
||||
import me.StevenLawson.TotalFreedomMod.TFM_ConfigEntry;
|
||||
import me.StevenLawson.TotalFreedomMod.TFM_Log;
|
||||
@ -19,6 +17,9 @@ import org.bukkit.Bukkit;
|
||||
|
||||
public class TFM_HTTPD_Manager
|
||||
{
|
||||
@Deprecated
|
||||
public static String MIME_DEFAULT_BINARY = "application/octet-stream";
|
||||
//
|
||||
private static final Pattern EXT_REGEX = Pattern.compile("\\.([^\\.\\s]+)$");
|
||||
//
|
||||
public static final int PORT = TFM_ConfigEntry.HTTPD_PORT.getInteger();
|
||||
@ -69,36 +70,118 @@ public class TFM_HTTPD_Manager
|
||||
|
||||
private static enum ModuleType
|
||||
{
|
||||
DUMP(false, "dump"),
|
||||
HELP(true, "help"),
|
||||
LIST(true, "list"),
|
||||
FILE(false, "file"),
|
||||
SCHEMATIC(false, "schematic"),
|
||||
PERMBANS(false, "permbans");
|
||||
DUMP(new ModuleExecutable(false, "dump")
|
||||
{
|
||||
@Override
|
||||
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;
|
||||
}
|
||||
|
||||
private abstract static class ModuleExecutable
|
||||
{
|
||||
private final boolean runOnBukkitThread;
|
||||
private final String name;
|
||||
|
||||
private ModuleType(boolean runOnBukkitThread, String name)
|
||||
public ModuleExecutable(boolean runOnBukkitThread, String name)
|
||||
{
|
||||
this.runOnBukkitThread = runOnBukkitThread;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public boolean isRunOnBukkitThread()
|
||||
public Response execute(final HTTPSession session)
|
||||
{
|
||||
return runOnBukkitThread;
|
||||
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 ModuleExecutable getModuleExecutable()
|
||||
{
|
||||
return moduleExecutable;
|
||||
}
|
||||
|
||||
private static ModuleType getByName(String needle)
|
||||
{
|
||||
for (ModuleType type : values())
|
||||
{
|
||||
if (type.getName().equalsIgnoreCase(needle))
|
||||
if (type.getModuleExecutable().getName().equalsIgnoreCase(needle))
|
||||
{
|
||||
return type;
|
||||
}
|
||||
@ -120,68 +203,15 @@ public class TFM_HTTPD_Manager
|
||||
}
|
||||
|
||||
@Override
|
||||
public Response serve(
|
||||
final String uri,
|
||||
final Method method,
|
||||
final Map<String, String> headers,
|
||||
final Map<String, String> params,
|
||||
final Map<String, String> files,
|
||||
final Socket socket)
|
||||
public Response serve(HTTPSession session)
|
||||
{
|
||||
Response response = null;
|
||||
Response response;
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
final String[] args = StringUtils.split(uri, "/");
|
||||
final String[] args = StringUtils.split(session.getUri(), "/");
|
||||
final ModuleType moduleType = args.length >= 1 ? ModuleType.getByName(args[0]) : ModuleType.FILE;
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
response = moduleType.getModuleExecutable().execute(session);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@ -215,10 +245,10 @@ public class TFM_HTTPD_Manager
|
||||
|
||||
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());
|
||||
}
|
||||
catch (IOException ex)
|
||||
|
@ -1,8 +1,10 @@
|
||||
package me.StevenLawson.TotalFreedomMod.HTTPD;
|
||||
|
||||
import java.net.Socket;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import me.StevenLawson.TotalFreedomMod.HTTPD.NanoHTTPD.*;
|
||||
import me.StevenLawson.TotalFreedomMod.TFM_Log;
|
||||
|
||||
public abstract class TFM_HTTPD_Module
|
||||
{
|
||||
@ -10,17 +12,17 @@ public abstract class TFM_HTTPD_Module
|
||||
protected final Method method;
|
||||
protected final Map<String, String> headers;
|
||||
protected final Map<String, String> params;
|
||||
protected final Map<String, String> files;
|
||||
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.method = method;
|
||||
this.headers = headers;
|
||||
this.params = params;
|
||||
this.files = files;
|
||||
this.socket = socket;
|
||||
this.uri = session.getUri();
|
||||
this.method = session.getMethod();
|
||||
this.headers = session.getHeaders();
|
||||
this.params = session.getParms();
|
||||
this.socket = session.getSocket();
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
public String getBody()
|
||||
@ -47,4 +49,20 @@ public abstract class TFM_HTTPD_Module
|
||||
{
|
||||
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