正在查看: Your TV v2.0.2 应用的 NanoHTTPD.java JAVA 源代码文件
本页面展示 JAVA 反编译生成的源代码文件,支持语法高亮显示。 仅供安全研究与技术分析使用,严禁用于任何非法用途。请遵守相关法律法规。
正在查看: Your TV v2.0.2 应用的 NanoHTTPD.java JAVA 源代码文件
本页面展示 JAVA 反编译生成的源代码文件,支持语法高亮显示。 仅供安全研究与技术分析使用,严禁用于任何非法用途。请遵守相关法律法规。
package fi.iki.elonen;
import A.g;
import androidx.media3.exoplayer.rtsp.RtspHeaders;
import com.bumptech.glide.load.Key;
import com.tencent.smtt.sdk.TbsListener;
import com.tencent.smtt.sdk.TbsVideoCacheTask;
import j$.util.DesugarCollections;
import j$.util.DesugarTimeZone;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.RandomAccessFile;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.net.URLDecoder;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.security.KeyStore;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.GZIPOutputStream;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.SSLServerSocketFactory;
import javax.net.ssl.TrustManagerFactory;
import okhttp3.internal.http2.Http2Stream;
import okhttp3.internal.ws.RealWebSocket;
import org.bouncycastle.asn1.a;
public abstract class NanoHTTPD {
public static final String MIME_HTML = "text/html";
public static final String MIME_PLAINTEXT = "text/plain";
protected static Map<String, String> MIME_TYPES = null;
private static final String QUERY_STRING_PARAMETER = "NanoHttpd.QUERY_STRING";
public static final int SOCKET_READ_TIMEOUT = 5000;
protected AsyncRunner asyncRunner;
private final String hostname;
private final int myPort;
private volatile ServerSocket myServerSocket;
private Thread myThread;
private ServerSocketFactory serverSocketFactory;
private TempFileManagerFactory tempFileManagerFactory;
private static final String CONTENT_DISPOSITION_REGEX = "([ |\t]*Content-Disposition[ |\t]*:)(.*)";
private static final Pattern CONTENT_DISPOSITION_PATTERN = Pattern.compile(CONTENT_DISPOSITION_REGEX, 2);
private static final String CONTENT_TYPE_REGEX = "([ |\t]*content-type[ |\t]*:)(.*)";
private static final Pattern CONTENT_TYPE_PATTERN = Pattern.compile(CONTENT_TYPE_REGEX, 2);
private static final String CONTENT_DISPOSITION_ATTRIBUTE_REGEX = "[ |\t]*([a-zA-Z]*)[ |\t]*=[ |\t]*['|\"]([^\"^']*)['|\"]";
private static final Pattern CONTENT_DISPOSITION_ATTRIBUTE_PATTERN = Pattern.compile(CONTENT_DISPOSITION_ATTRIBUTE_REGEX);
private static final Logger LOG = Logger.getLogger(NanoHTTPD.class.getName());
public interface AsyncRunner {
void closeAll();
void closed(ClientHandler clientHandler);
void exec(ClientHandler clientHandler);
}
public class ClientHandler implements Runnable {
private final Socket acceptSocket;
private final InputStream inputStream;
public ClientHandler(InputStream inputStream, Socket socket) {
this.inputStream = inputStream;
this.acceptSocket = socket;
}
public void close() {
NanoHTTPD.safeClose(this.inputStream);
NanoHTTPD.safeClose(this.acceptSocket);
}
@Override
public void run() {
OutputStream outputStream;
OutputStream outputStream2 = null;
try {
try {
outputStream = this.acceptSocket.getOutputStream();
} catch (Exception e2) {
e = e2;
}
} catch (Throwable th) {
th = th;
}
try {
HTTPSession hTTPSession = NanoHTTPD.this.new HTTPSession(NanoHTTPD.this.tempFileManagerFactory.create(), this.inputStream, outputStream, this.acceptSocket.getInetAddress());
while (!this.acceptSocket.isClosed()) {
hTTPSession.execute();
}
NanoHTTPD.safeClose(outputStream);
NanoHTTPD.safeClose(this.inputStream);
NanoHTTPD.safeClose(this.acceptSocket);
NanoHTTPD.this.asyncRunner.closed(this);
} catch (Exception e3) {
e = e3;
outputStream2 = outputStream;
if ((!(e instanceof SocketException) || !"NanoHttpd Shutdown".equals(e.getMessage())) && !(e instanceof SocketTimeoutException)) {
NanoHTTPD.LOG.log(Level.SEVERE, "Communication with the client broken, or an bug in the handler code", (Throwable) e);
}
NanoHTTPD.safeClose(outputStream2);
NanoHTTPD.safeClose(this.inputStream);
NanoHTTPD.safeClose(this.acceptSocket);
NanoHTTPD.this.asyncRunner.closed(this);
} catch (Throwable th2) {
th = th2;
outputStream2 = outputStream;
NanoHTTPD.safeClose(outputStream2);
NanoHTTPD.safeClose(this.inputStream);
NanoHTTPD.safeClose(this.acceptSocket);
NanoHTTPD.this.asyncRunner.closed(this);
throw th;
}
}
}
public static class ContentType {
private static final String ASCII_ENCODING = "US-ASCII";
private static final String MULTIPART_FORM_DATA_HEADER = "multipart/form-data";
private final String boundary;
private final String contentType;
private final String contentTypeHeader;
private final String encoding;
private static final String CONTENT_REGEX = "[ |\t]*([^/^ ^;^,]+/[^ ^;^,]+)";
private static final Pattern MIME_PATTERN = Pattern.compile(CONTENT_REGEX, 2);
private static final String CHARSET_REGEX = "[ |\t]*(charset)[ |\t]*=[ |\t]*['|\"]?([^\"^'^;^,]*)['|\"]?";
private static final Pattern CHARSET_PATTERN = Pattern.compile(CHARSET_REGEX, 2);
private static final String BOUNDARY_REGEX = "[ |\t]*(boundary)[ |\t]*=[ |\t]*['|\"]?([^\"^'^;^,]*)['|\"]?";
private static final Pattern BOUNDARY_PATTERN = Pattern.compile(BOUNDARY_REGEX, 2);
public ContentType(String str) {
this.contentTypeHeader = str;
if (str != null) {
this.contentType = getDetailFromContentHeader(str, MIME_PATTERN, "", 1);
this.encoding = getDetailFromContentHeader(str, CHARSET_PATTERN, null, 2);
} else {
this.contentType = "";
this.encoding = Key.STRING_CHARSET_NAME;
}
if (MULTIPART_FORM_DATA_HEADER.equalsIgnoreCase(this.contentType)) {
this.boundary = getDetailFromContentHeader(str, BOUNDARY_PATTERN, null, 2);
} else {
this.boundary = null;
}
}
private String getDetailFromContentHeader(String str, Pattern pattern, String str2, int i2) {
Matcher matcher = pattern.matcher(str);
return matcher.find() ? matcher.group(i2) : str2;
}
public String getBoundary() {
return this.boundary;
}
public String getContentType() {
return this.contentType;
}
public String getContentTypeHeader() {
return this.contentTypeHeader;
}
public String getEncoding() {
String str = this.encoding;
return str == null ? ASCII_ENCODING : str;
}
public boolean isMultipart() {
return MULTIPART_FORM_DATA_HEADER.equalsIgnoreCase(this.contentType);
}
public ContentType tryUTF8() {
return this.encoding == null ? new ContentType(a.k(new StringBuilder(), this.contentTypeHeader, "; charset=UTF-8")) : this;
}
}
public static class Cookie {
private final String f4790e;
private final String f4791n;
private final String f4792v;
public Cookie(String str, String str2) {
this(str, str2, 30);
}
public static String getHTTPTime(int i2) {
Calendar calendar = Calendar.getInstance();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
simpleDateFormat.setTimeZone(DesugarTimeZone.getTimeZone("GMT"));
calendar.add(5, i2);
return simpleDateFormat.format(calendar.getTime());
}
public String getHTTPHeader() {
return this.f4791n + "=" + this.f4792v + "; expires=" + this.f4790e;
}
public Cookie(String str, String str2, int i2) {
this.f4791n = str;
this.f4792v = str2;
this.f4790e = getHTTPTime(i2);
}
public Cookie(String str, String str2, String str3) {
this.f4791n = str;
this.f4792v = str2;
this.f4790e = str3;
}
}
public class CookieHandler implements Iterable<String> {
private final HashMap<String, String> cookies = new HashMap<>();
private final ArrayList<Cookie> queue = new ArrayList<>();
public CookieHandler(Map<String, String> map) {
String str = map.get("cookie");
if (str != null) {
for (String str2 : str.split(";")) {
String[] split = str2.trim().split("=");
if (split.length == 2) {
this.cookies.put(split[0], split[1]);
}
}
}
}
public void delete(String str) {
set(str, "-delete-", -30);
}
@Override
public Iterator<String> iterator() {
return this.cookies.keySet().iterator();
}
public String read(String str) {
return this.cookies.get(str);
}
public void set(Cookie cookie) {
this.queue.add(cookie);
}
public void unloadQueue(Response response) {
Iterator<Cookie> it = this.queue.iterator();
while (it.hasNext()) {
response.addHeader("Set-Cookie", it.next().getHTTPHeader());
}
}
public void set(String str, String str2, int i2) {
this.queue.add(new Cookie(str, str2, Cookie.getHTTPTime(i2)));
}
}
public static class DefaultAsyncRunner implements AsyncRunner {
private long requestCount;
private final List<ClientHandler> running = DesugarCollections.synchronizedList(new ArrayList());
@Override
public void closeAll() {
Iterator it = new ArrayList(this.running).iterator();
while (it.hasNext()) {
((ClientHandler) it.next()).close();
}
}
@Override
public void closed(ClientHandler clientHandler) {
this.running.remove(clientHandler);
}
@Override
public void exec(ClientHandler clientHandler) {
this.requestCount++;
Thread thread = new Thread(clientHandler);
thread.setDaemon(true);
thread.setName("NanoHttpd Request Processor (#" + this.requestCount + ")");
this.running.add(clientHandler);
thread.start();
}
public List<ClientHandler> getRunning() {
return this.running;
}
}
public static class DefaultServerSocketFactory implements ServerSocketFactory {
@Override
public ServerSocket create() {
return new ServerSocket();
}
}
public static class DefaultTempFile implements TempFile {
private final File file;
private final OutputStream fstream;
public DefaultTempFile(File file) {
File createTempFile = File.createTempFile("NanoHTTPD-", "", file);
this.file = createTempFile;
this.fstream = new FileOutputStream(createTempFile);
}
@Override
public void delete() {
NanoHTTPD.safeClose(this.fstream);
if (this.file.delete()) {
return;
}
throw new Exception("could not delete temporary file: " + this.file.getAbsolutePath());
}
@Override
public String getName() {
return this.file.getAbsolutePath();
}
@Override
public OutputStream open() {
return this.fstream;
}
}
public static class DefaultTempFileManager implements TempFileManager {
private final List<TempFile> tempFiles;
private final File tmpdir;
public DefaultTempFileManager() {
File file = new File(System.getProperty("java.io.tmpdir"));
this.tmpdir = file;
if (!file.exists()) {
file.mkdirs();
}
this.tempFiles = new ArrayList();
}
@Override
public void clear() {
Iterator<TempFile> it = this.tempFiles.iterator();
while (it.hasNext()) {
try {
it.next().delete();
} catch (Exception e2) {
NanoHTTPD.LOG.log(Level.WARNING, "could not delete file ", (Throwable) e2);
}
}
this.tempFiles.clear();
}
@Override
public TempFile createTempFile(String str) {
DefaultTempFile defaultTempFile = new DefaultTempFile(this.tmpdir);
this.tempFiles.add(defaultTempFile);
return defaultTempFile;
}
}
public class DefaultTempFileManagerFactory implements TempFileManagerFactory {
private DefaultTempFileManagerFactory() {
}
@Override
public TempFileManager create() {
return new DefaultTempFileManager();
}
}
public interface IHTTPSession {
void execute();
CookieHandler getCookies();
Map<String, String> getHeaders();
InputStream getInputStream();
Method getMethod();
Map<String, List<String>> getParameters();
@Deprecated
Map<String, String> getParms();
String getQueryParameterString();
String getRemoteHostName();
String getRemoteIpAddress();
String getUri();
void parseBody(Map<String, String> map);
}
public enum Method {
GET,
PUT,
POST,
DELETE,
HEAD,
OPTIONS,
TRACE,
CONNECT,
PATCH,
PROPFIND,
PROPPATCH,
MKCOL,
MOVE,
COPY,
LOCK,
UNLOCK;
public static Method lookup(String str) {
if (str == null) {
return null;
}
try {
return valueOf(str);
} catch (IllegalArgumentException unused) {
return null;
}
}
}
public static class Response implements Closeable {
private boolean chunkedTransfer;
private long contentLength;
private InputStream data;
private boolean encodeAsGzip;
private boolean keepAlive;
private String mimeType;
private Method requestMethod;
private IStatus status;
private final Map<String, String> header = new HashMap<String, String>() {
@Override
public String put(String str, String str2) {
Response.this.lowerCaseHeader.put(str == null ? str : str.toLowerCase(), str2);
return (String) super.put((AnonymousClass1) str, str2);
}
};
private final Map<String, String> lowerCaseHeader = new HashMap();
public interface IStatus {
String getDescription();
int getRequestStatus();
}
public enum Status implements IStatus {
SWITCH_PROTOCOL(101, "Switching Protocols"),
OK(200, "OK"),
CREATED(TbsListener.ErrorCode.EXCEED_UNZIP_RETRY_NUM, "Created"),
ACCEPTED(TbsListener.ErrorCode.APK_PATH_ERROR, "Accepted"),
NO_CONTENT(TbsListener.ErrorCode.APK_INVALID, "No Content"),
PARTIAL_CONTENT(TbsListener.ErrorCode.UNZIP_IO_ERROR, "Partial Content"),
MULTI_STATUS(TbsListener.ErrorCode.UNZIP_OTHER_ERROR, "Multi-Status"),
REDIRECT(301, "Moved Permanently"),
FOUND(302, "Found"),
REDIRECT_SEE_OTHER(TbsListener.ErrorCode.ERROR_UNMATCH_TBSCORE_VER, "See Other"),
NOT_MODIFIED(304, "Not Modified"),
TEMPORARY_REDIRECT(307, "Temporary Redirect"),
BAD_REQUEST(TbsListener.ErrorCode.INFO_CODE_BASE, "Bad Request"),
UNAUTHORIZED(TbsListener.ErrorCode.INFO_FORCE_SYSTEM_WEBVIEW_INNER, "Unauthorized"),
FORBIDDEN(TbsListener.ErrorCode.INFO_MISS_SDKEXTENSION_JAR, "Forbidden"),
NOT_FOUND(TbsListener.ErrorCode.INFO_CORE_NOT_EXIST, "Not Found"),
METHOD_NOT_ALLOWED(TbsListener.ErrorCode.INFO_CAN_NOT_LOAD_TBS, "Method Not Allowed"),
NOT_ACCEPTABLE(TbsListener.ErrorCode.INFO_MISS_SDKEXTENSION_JAR_OLD, "Not Acceptable"),
REQUEST_TIMEOUT(TbsListener.ErrorCode.INFO_CAN_NOT_DISABLED_BY_CRASH, "Request Timeout"),
CONFLICT(TbsListener.ErrorCode.INFO_CAN_NOT_USE_X5_TBS_AVAILABLE, "Conflict"),
GONE(TbsListener.ErrorCode.INFO_CAN_NOT_USE_X5_TBS_NOTAVAILABLE, "Gone"),
LENGTH_REQUIRED(TbsListener.ErrorCode.INFO_CAN_NOT_USE_X5_FINAL_REASON, "Length Required"),
PRECONDITION_FAILED(TbsListener.ErrorCode.INFO_MISS_SDKEXTENSION_JAR_WITHOUT_FUSION_DEX, "Precondition Failed"),
PAYLOAD_TOO_LARGE(TbsListener.ErrorCode.INFO_MISS_SDKEXTENSION_JAR_WITH_FUSION_DEX, "Payload Too Large"),
UNSUPPORTED_MEDIA_TYPE(TbsListener.ErrorCode.INFO_INITX5_FALSE_DEFAULT, "Unsupported Media Type"),
RANGE_NOT_SATISFIABLE(TbsListener.ErrorCode.INFO_USE_BACKUP_FILE_INSTALL_BY_SERVER, "Requested Range Not Satisfiable"),
EXPECTATION_FAILED(TbsListener.ErrorCode.INFO_TEMP_CORE_EXIST_CONF_ERROR, "Expectation Failed"),
TOO_MANY_REQUESTS(429, "Too Many Requests"),
INTERNAL_ERROR(TbsListener.ErrorCode.INFO_CODE_MINIQB, "Internal Server Error"),
NOT_IMPLEMENTED(501, "Not Implemented"),
SERVICE_UNAVAILABLE(TbsListener.ErrorCode.INFO_CODE_MINIQB_STARTMINIQBTOLOADURL_SUCCESS, "Service Unavailable"),
UNSUPPORTED_HTTP_VERSION(TbsListener.ErrorCode.INFO_CODE_FILEREADER_OPENFILEREADER_COUNTS, "HTTP Version Not Supported");
private final String description;
private final int requestStatus;
Status(int i2, String str) {
this.requestStatus = i2;
this.description = str;
}
public static Status lookup(int i2) {
for (Status status : values()) {
if (status.getRequestStatus() == i2) {
return status;
}
}
return null;
}
@Override
public String getDescription() {
return "" + this.requestStatus + " " + this.description;
}
@Override
public int getRequestStatus() {
return this.requestStatus;
}
}
public Response(IStatus iStatus, String str, InputStream inputStream, long j2) {
this.status = iStatus;
this.mimeType = str;
if (inputStream == null) {
this.data = new ByteArrayInputStream(new byte[0]);
this.contentLength = 0L;
} else {
this.data = inputStream;
this.contentLength = j2;
}
this.chunkedTransfer = this.contentLength < 0;
this.keepAlive = true;
}
private void sendBody(OutputStream outputStream, long j2) {
byte[] bArr = new byte[(int) Http2Stream.EMIT_BUFFER_SIZE];
boolean z2 = j2 == -1;
while (true) {
if (j2 <= 0 && !z2) {
return;
}
int read = this.data.read(bArr, 0, (int) (z2 ? 16384L : Math.min(j2, Http2Stream.EMIT_BUFFER_SIZE)));
if (read <= 0) {
return;
}
outputStream.write(bArr, 0, read);
if (!z2) {
j2 -= read;
}
}
}
private void sendBodyWithCorrectEncoding(OutputStream outputStream, long j2) {
if (!this.encodeAsGzip) {
sendBody(outputStream, j2);
return;
}
GZIPOutputStream gZIPOutputStream = new GZIPOutputStream(outputStream);
sendBody(gZIPOutputStream, -1L);
gZIPOutputStream.finish();
}
private void sendBodyWithCorrectTransferAndEncoding(OutputStream outputStream, long j2) {
if (this.requestMethod == Method.HEAD || !this.chunkedTransfer) {
sendBodyWithCorrectEncoding(outputStream, j2);
return;
}
ChunkedOutputStream chunkedOutputStream = new ChunkedOutputStream(outputStream);
sendBodyWithCorrectEncoding(chunkedOutputStream, -1L);
chunkedOutputStream.finish();
}
public void addHeader(String str, String str2) {
this.header.put(str, str2);
}
@Override
public void close() {
InputStream inputStream = this.data;
if (inputStream != null) {
inputStream.close();
}
}
public void closeConnection(boolean z2) {
if (z2) {
this.header.put("connection", "close");
} else {
this.header.remove("connection");
}
}
public InputStream getData() {
return this.data;
}
public String getHeader(String str) {
return this.lowerCaseHeader.get(str.toLowerCase());
}
public String getMimeType() {
return this.mimeType;
}
public Method getRequestMethod() {
return this.requestMethod;
}
public IStatus getStatus() {
return this.status;
}
public boolean isCloseConnection() {
return "close".equals(getHeader("connection"));
}
public void printHeader(PrintWriter printWriter, String str, String str2) {
printWriter.append((CharSequence) str).append(": ").append((CharSequence) str2).append("\r\n");
}
public void send(OutputStream outputStream) {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("E, d MMM yyyy HH:mm:ss 'GMT'", Locale.US);
simpleDateFormat.setTimeZone(DesugarTimeZone.getTimeZone("GMT"));
try {
if (this.status == null) {
throw new Error("sendResponse(): Status can't be null.");
}
PrintWriter printWriter = new PrintWriter((Writer) new BufferedWriter(new OutputStreamWriter(outputStream, new ContentType(this.mimeType).getEncoding())), false);
printWriter.append("HTTP/1.1 ").append((CharSequence) this.status.getDescription()).append(" \r\n");
String str = this.mimeType;
if (str != null) {
printHeader(printWriter, RtspHeaders.CONTENT_TYPE, str);
}
if (getHeader("date") == null) {
printHeader(printWriter, RtspHeaders.DATE, simpleDateFormat.format(new Date()));
}
for (Map.Entry<String, String> entry : this.header.entrySet()) {
printHeader(printWriter, entry.getKey(), entry.getValue());
}
if (getHeader("connection") == null) {
printHeader(printWriter, RtspHeaders.CONNECTION, this.keepAlive ? "keep-alive" : "close");
}
if (getHeader("content-length") != null) {
this.encodeAsGzip = false;
}
if (this.encodeAsGzip) {
printHeader(printWriter, RtspHeaders.CONTENT_ENCODING, "gzip");
setChunkedTransfer(true);
}
long j2 = this.data != null ? this.contentLength : 0L;
if (this.requestMethod != Method.HEAD && this.chunkedTransfer) {
printHeader(printWriter, "Transfer-Encoding", "chunked");
} else if (!this.encodeAsGzip) {
j2 = sendContentLengthHeaderIfNotAlreadyPresent(printWriter, j2);
}
printWriter.append("\r\n");
printWriter.flush();
sendBodyWithCorrectTransferAndEncoding(outputStream, j2);
outputStream.flush();
NanoHTTPD.safeClose(this.data);
} catch (IOException e2) {
NanoHTTPD.LOG.log(Level.SEVERE, "Could not send response to the client", (Throwable) e2);
}
}
public long sendContentLengthHeaderIfNotAlreadyPresent(PrintWriter printWriter, long j2) {
String header = getHeader("content-length");
if (header != null) {
try {
j2 = Long.parseLong(header);
} catch (NumberFormatException unused) {
NanoHTTPD.LOG.severe("content-length was no number ".concat(header));
}
}
printWriter.print("Content-Length: " + j2 + "\r\n");
return j2;
}
public void setChunkedTransfer(boolean z2) {
this.chunkedTransfer = z2;
}
public void setData(InputStream inputStream) {
this.data = inputStream;
}
public void setGzipEncoding(boolean z2) {
this.encodeAsGzip = z2;
}
public void setKeepAlive(boolean z2) {
this.keepAlive = z2;
}
public void setMimeType(String str) {
this.mimeType = str;
}
public void setRequestMethod(Method method) {
this.requestMethod = method;
}
public void setStatus(IStatus iStatus) {
this.status = iStatus;
}
public static class ChunkedOutputStream extends FilterOutputStream {
public ChunkedOutputStream(OutputStream outputStream) {
super(outputStream);
}
public void finish() {
((FilterOutputStream) this).out.write("0\r\n\r\n".getBytes());
}
@Override
public void write(int i2) {
write(new byte[]{(byte) i2}, 0, 1);
}
@Override
public void write(byte[] bArr) {
write(bArr, 0, bArr.length);
}
@Override
public void write(byte[] bArr, int i2, int i3) {
if (i3 == 0) {
return;
}
((FilterOutputStream) this).out.write(String.format("%x\r\n", Integer.valueOf(i3)).getBytes());
((FilterOutputStream) this).out.write(bArr, i2, i3);
((FilterOutputStream) this).out.write("\r\n".getBytes());
}
}
}
public static class SecureServerSocketFactory implements ServerSocketFactory {
private String[] sslProtocols;
private SSLServerSocketFactory sslServerSocketFactory;
public SecureServerSocketFactory(SSLServerSocketFactory sSLServerSocketFactory, String[] strArr) {
this.sslServerSocketFactory = sSLServerSocketFactory;
this.sslProtocols = strArr;
}
@Override
public ServerSocket create() {
SSLServerSocket sSLServerSocket = (SSLServerSocket) this.sslServerSocketFactory.createServerSocket();
String[] strArr = this.sslProtocols;
if (strArr != null) {
sSLServerSocket.setEnabledProtocols(strArr);
} else {
sSLServerSocket.setEnabledProtocols(sSLServerSocket.getSupportedProtocols());
}
sSLServerSocket.setUseClientMode(false);
sSLServerSocket.setWantClientAuth(false);
sSLServerSocket.setNeedClientAuth(false);
return sSLServerSocket;
}
}
public class ServerRunnable implements Runnable {
private IOException bindException;
private boolean hasBinded = false;
private final int timeout;
public ServerRunnable(int i2) {
this.timeout = i2;
}
@Override
public void run() {
try {
NanoHTTPD.this.myServerSocket.bind(NanoHTTPD.this.hostname != null ? new InetSocketAddress(NanoHTTPD.this.hostname, NanoHTTPD.this.myPort) : new InetSocketAddress(NanoHTTPD.this.myPort));
this.hasBinded = true;
do {
try {
Socket accept = NanoHTTPD.this.myServerSocket.accept();
int i2 = this.timeout;
if (i2 > 0) {
accept.setSoTimeout(i2);
}
InputStream inputStream = accept.getInputStream();
NanoHTTPD nanoHTTPD = NanoHTTPD.this;
nanoHTTPD.asyncRunner.exec(nanoHTTPD.createClientHandler(accept, inputStream));
} catch (IOException e2) {
NanoHTTPD.LOG.log(Level.FINE, "Communication with the client broken", (Throwable) e2);
}
} while (!NanoHTTPD.this.myServerSocket.isClosed());
} catch (IOException e3) {
this.bindException = e3;
}
}
}
public interface ServerSocketFactory {
ServerSocket create();
}
public interface TempFile {
void delete();
String getName();
OutputStream open();
}
public interface TempFileManager {
void clear();
TempFile createTempFile(String str);
}
public interface TempFileManagerFactory {
TempFileManager create();
}
public NanoHTTPD(int i2) {
this(null, i2);
}
public static Map<String, List<String>> decodeParameters(Map<String, String> map) {
return decodeParameters(map.get(QUERY_STRING_PARAMETER));
}
public static String decodePercent(String str) {
try {
return URLDecoder.decode(str, "UTF8");
} catch (UnsupportedEncodingException e2) {
LOG.log(Level.WARNING, "Encoding not supported, ignored", (Throwable) e2);
return null;
}
}
public static String getMimeTypeForFile(String str) {
int lastIndexOf = str.lastIndexOf(46);
String str2 = lastIndexOf >= 0 ? mimeTypes().get(str.substring(lastIndexOf + 1).toLowerCase()) : null;
return str2 == null ? "application/octet-stream" : str2;
}
private static void loadMimeTypes(Map<String, String> map, String str) {
try {
Enumeration<URL> resources = NanoHTTPD.class.getClassLoader().getResources(str);
while (resources.hasMoreElements()) {
URL nextElement = resources.nextElement();
Properties properties = new Properties();
InputStream inputStream = null;
try {
try {
inputStream = nextElement.openStream();
properties.load(inputStream);
} catch (IOException e2) {
LOG.log(Level.SEVERE, "could not load mimetypes from " + nextElement, (Throwable) e2);
}
safeClose(inputStream);
map.putAll(properties);
} catch (Throwable th) {
safeClose(inputStream);
throw th;
}
}
} catch (IOException unused) {
LOG.log(Level.INFO, "no mime types available at " + str);
}
}
public static SSLServerSocketFactory makeSSLSocketFactory(KeyStore keyStore, KeyManager[] keyManagerArr) {
try {
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
SSLContext sSLContext = SSLContext.getInstance("TLS");
sSLContext.init(keyManagerArr, trustManagerFactory.getTrustManagers(), null);
return sSLContext.getServerSocketFactory();
} catch (Exception e2) {
throw new IOException(e2.getMessage());
}
}
public static Map<String, String> mimeTypes() {
if (MIME_TYPES == null) {
HashMap hashMap = new HashMap();
MIME_TYPES = hashMap;
loadMimeTypes(hashMap, "META-INF/nanohttpd/default-mimetypes.properties");
loadMimeTypes(MIME_TYPES, "META-INF/nanohttpd/mimetypes.properties");
if (MIME_TYPES.isEmpty()) {
LOG.log(Level.WARNING, "no mime types found in the classpath! please provide mimetypes.properties");
}
}
return MIME_TYPES;
}
public static Response newChunkedResponse(Response.IStatus iStatus, String str, InputStream inputStream) {
return new Response(iStatus, str, inputStream, -1L);
}
public static Response newFixedLengthResponse(Response.IStatus iStatus, String str, InputStream inputStream, long j2) {
return new Response(iStatus, str, inputStream, j2);
}
public static final void safeClose(Object obj) {
if (obj != null) {
try {
if (obj instanceof Closeable) {
((Closeable) obj).close();
} else if (obj instanceof Socket) {
((Socket) obj).close();
} else {
if (!(obj instanceof ServerSocket)) {
throw new IllegalArgumentException("Unknown object to close");
}
((ServerSocket) obj).close();
}
} catch (IOException e2) {
LOG.log(Level.SEVERE, "Could not close", (Throwable) e2);
}
}
}
public synchronized void closeAllConnections() {
stop();
}
public ClientHandler createClientHandler(Socket socket, InputStream inputStream) {
return new ClientHandler(inputStream, socket);
}
public ServerRunnable createServerRunnable(int i2) {
return new ServerRunnable(i2);
}
public String getHostname() {
return this.hostname;
}
public final int getListeningPort() {
if (this.myServerSocket == null) {
return -1;
}
return this.myServerSocket.getLocalPort();
}
public ServerSocketFactory getServerSocketFactory() {
return this.serverSocketFactory;
}
public TempFileManagerFactory getTempFileManagerFactory() {
return this.tempFileManagerFactory;
}
public final boolean isAlive() {
return wasStarted() && !this.myServerSocket.isClosed() && this.myThread.isAlive();
}
public void makeSecure(SSLServerSocketFactory sSLServerSocketFactory, String[] strArr) {
this.serverSocketFactory = new SecureServerSocketFactory(sSLServerSocketFactory, strArr);
}
public Response serve(IHTTPSession iHTTPSession) {
HashMap hashMap = new HashMap();
Method method = iHTTPSession.getMethod();
if (Method.PUT.equals(method) || Method.POST.equals(method)) {
try {
iHTTPSession.parseBody(hashMap);
} catch (ResponseException e2) {
return newFixedLengthResponse(e2.getStatus(), MIME_PLAINTEXT, e2.getMessage());
} catch (IOException e3) {
return newFixedLengthResponse(Response.Status.INTERNAL_ERROR, MIME_PLAINTEXT, "SERVER INTERNAL ERROR: IOException: " + e3.getMessage());
}
}
Map<String, String> parms = iHTTPSession.getParms();
parms.put(QUERY_STRING_PARAMETER, iHTTPSession.getQueryParameterString());
return serve(iHTTPSession.getUri(), method, iHTTPSession.getHeaders(), parms, hashMap);
}
public void setAsyncRunner(AsyncRunner asyncRunner) {
this.asyncRunner = asyncRunner;
}
public void setServerSocketFactory(ServerSocketFactory serverSocketFactory) {
this.serverSocketFactory = serverSocketFactory;
}
public void setTempFileManagerFactory(TempFileManagerFactory tempFileManagerFactory) {
this.tempFileManagerFactory = tempFileManagerFactory;
}
public void start() {
start(5000);
}
public void stop() {
try {
safeClose(this.myServerSocket);
this.asyncRunner.closeAll();
Thread thread = this.myThread;
if (thread != null) {
thread.join();
}
} catch (Exception e2) {
LOG.log(Level.SEVERE, "Could not stop all connections", (Throwable) e2);
}
}
public boolean useGzipWhenAccepted(Response response) {
if (response.getMimeType() != null) {
return response.getMimeType().toLowerCase().contains("text/") || response.getMimeType().toLowerCase().contains("/json");
}
return false;
}
public final boolean wasStarted() {
return (this.myServerSocket == null || this.myThread == null) ? false : true;
}
public static final class ResponseException extends Exception {
private static final long serialVersionUID = 6569838532917408380L;
private final Response.Status status;
public ResponseException(Response.Status status, String str) {
super(str);
this.status = status;
}
public Response.Status getStatus() {
return this.status;
}
public ResponseException(Response.Status status, String str, Exception exc) {
super(str, exc);
this.status = status;
}
}
public NanoHTTPD(String str, int i2) {
this.serverSocketFactory = new DefaultServerSocketFactory();
this.hostname = str;
this.myPort = i2;
setTempFileManagerFactory(new DefaultTempFileManagerFactory());
setAsyncRunner(new DefaultAsyncRunner());
}
public static Map<String, List<String>> decodeParameters(String str) {
HashMap hashMap = new HashMap();
if (str != null) {
StringTokenizer stringTokenizer = new StringTokenizer(str, "&");
while (stringTokenizer.hasMoreTokens()) {
String nextToken = stringTokenizer.nextToken();
int indexOf = nextToken.indexOf(61);
String trim = (indexOf >= 0 ? decodePercent(nextToken.substring(0, indexOf)) : decodePercent(nextToken)).trim();
if (!hashMap.containsKey(trim)) {
hashMap.put(trim, new ArrayList());
}
String decodePercent = indexOf >= 0 ? decodePercent(nextToken.substring(indexOf + 1)) : null;
if (decodePercent != null) {
((List) hashMap.get(trim)).add(decodePercent);
}
}
}
return hashMap;
}
public static Response newFixedLengthResponse(Response.IStatus iStatus, String str, String str2) {
byte[] bArr;
ContentType contentType = new ContentType(str);
if (str2 == null) {
return newFixedLengthResponse(iStatus, str, new ByteArrayInputStream(new byte[0]), 0L);
}
try {
if (!Charset.forName(contentType.getEncoding()).newEncoder().canEncode(str2)) {
contentType = contentType.tryUTF8();
}
bArr = str2.getBytes(contentType.getEncoding());
} catch (UnsupportedEncodingException e2) {
LOG.log(Level.SEVERE, "encoding problem, responding nothing", (Throwable) e2);
bArr = new byte[0];
}
return newFixedLengthResponse(iStatus, contentType.getContentTypeHeader(), new ByteArrayInputStream(bArr), bArr.length);
}
public void start(int i2) {
start(i2, true);
}
public void start(int i2, boolean z2) {
this.myServerSocket = getServerSocketFactory().create();
this.myServerSocket.setReuseAddress(true);
ServerRunnable createServerRunnable = createServerRunnable(i2);
Thread thread = new Thread(createServerRunnable);
this.myThread = thread;
thread.setDaemon(z2);
this.myThread.setName("NanoHttpd Main Listener");
this.myThread.start();
while (!createServerRunnable.hasBinded && createServerRunnable.bindException == null) {
try {
Thread.sleep(10L);
} catch (Throwable unused) {
}
}
if (createServerRunnable.bindException != null) {
throw createServerRunnable.bindException;
}
}
public class HTTPSession implements IHTTPSession {
public static final int BUFSIZE = 8192;
public static final int MAX_HEADER_SIZE = 1024;
private static final int MEMORY_STORE_LIMIT = 1024;
private static final int REQUEST_BUFFER_LEN = 512;
private CookieHandler cookies;
private Map<String, String> headers;
private final BufferedInputStream inputStream;
private Method method;
private final OutputStream outputStream;
private Map<String, List<String>> parms;
private String protocolVersion;
private String queryParameterString;
private String remoteHostname;
private String remoteIp;
private int rlen;
private int splitbyte;
private final TempFileManager tempFileManager;
private String uri;
public HTTPSession(TempFileManager tempFileManager, InputStream inputStream, OutputStream outputStream) {
this.tempFileManager = tempFileManager;
this.inputStream = new BufferedInputStream(inputStream, 8192);
this.outputStream = outputStream;
}
private void decodeHeader(BufferedReader bufferedReader, Map<String, String> map, Map<String, List<String>> map2, Map<String, String> map3) {
String decodePercent;
try {
String readLine = bufferedReader.readLine();
if (readLine == null) {
return;
}
StringTokenizer stringTokenizer = new StringTokenizer(readLine);
if (!stringTokenizer.hasMoreTokens()) {
throw new ResponseException(Response.Status.BAD_REQUEST, "BAD REQUEST: Syntax error. Usage: GET /example/file.html");
}
map.put("method", stringTokenizer.nextToken());
if (!stringTokenizer.hasMoreTokens()) {
throw new ResponseException(Response.Status.BAD_REQUEST, "BAD REQUEST: Missing URI. Usage: GET /example/file.html");
}
String nextToken = stringTokenizer.nextToken();
int indexOf = nextToken.indexOf(63);
if (indexOf >= 0) {
decodeParms(nextToken.substring(indexOf + 1), map2);
decodePercent = NanoHTTPD.decodePercent(nextToken.substring(0, indexOf));
} else {
decodePercent = NanoHTTPD.decodePercent(nextToken);
}
if (stringTokenizer.hasMoreTokens()) {
this.protocolVersion = stringTokenizer.nextToken();
} else {
this.protocolVersion = "HTTP/1.1";
NanoHTTPD.LOG.log(Level.FINE, "no protocol version specified, strange. Assuming HTTP/1.1.");
}
String readLine2 = bufferedReader.readLine();
while (readLine2 != null && !readLine2.trim().isEmpty()) {
int indexOf2 = readLine2.indexOf(58);
if (indexOf2 >= 0) {
map3.put(readLine2.substring(0, indexOf2).trim().toLowerCase(Locale.US), readLine2.substring(indexOf2 + 1).trim());
}
readLine2 = bufferedReader.readLine();
}
map.put("uri", decodePercent);
} catch (IOException e2) {
throw new ResponseException(Response.Status.INTERNAL_ERROR, g.g(e2, new StringBuilder("SERVER INTERNAL ERROR: IOException: ")), e2);
}
}
private void decodeMultipartFormData(ContentType contentType, ByteBuffer byteBuffer, Map<String, List<String>> map, Map<String, String> map2) {
int i2;
try {
int[] boundaryPositions = getBoundaryPositions(byteBuffer, contentType.getBoundary().getBytes());
int i3 = 2;
if (boundaryPositions.length < 2) {
throw new ResponseException(Response.Status.BAD_REQUEST, "BAD REQUEST: Content type is multipart/form-data but contains less than two boundary strings.");
}
int i4 = 1024;
byte[] bArr = new byte[1024];
int i5 = 0;
int i6 = 0;
int i7 = 0;
while (true) {
int i8 = 1;
if (i6 >= boundaryPositions.length - 1) {
return;
}
byteBuffer.position(boundaryPositions[i6]);
int remaining = byteBuffer.remaining() < i4 ? byteBuffer.remaining() : i4;
byteBuffer.get(bArr, i5, remaining);
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(bArr, i5, remaining), Charset.forName(contentType.getEncoding())), remaining);
String readLine = bufferedReader.readLine();
if (readLine == null || !readLine.contains(contentType.getBoundary())) {
break;
}
String readLine2 = bufferedReader.readLine();
String str = null;
int i9 = i3;
String str2 = null;
String str3 = null;
while (readLine2 != null && readLine2.trim().length() > 0) {
Matcher matcher = NanoHTTPD.CONTENT_DISPOSITION_PATTERN.matcher(readLine2);
if (matcher.matches()) {
Matcher matcher2 = NanoHTTPD.CONTENT_DISPOSITION_ATTRIBUTE_PATTERN.matcher(matcher.group(i3));
while (matcher2.find()) {
String group = matcher2.group(i8);
if ("name".equalsIgnoreCase(group)) {
str = matcher2.group(2);
} else if (TbsVideoCacheTask.KEY_VIDEO_CACHE_PARAM_FILENAME.equalsIgnoreCase(group)) {
String group2 = matcher2.group(2);
if (!group2.isEmpty()) {
if (i7 > 0) {
str = str + String.valueOf(i7);
i7++;
} else {
i7++;
}
}
str2 = group2;
}
i8 = 1;
}
}
Matcher matcher3 = NanoHTTPD.CONTENT_TYPE_PATTERN.matcher(readLine2);
if (matcher3.matches()) {
i2 = 2;
str3 = matcher3.group(2).trim();
} else {
i2 = 2;
}
readLine2 = bufferedReader.readLine();
i9++;
i3 = i2;
i8 = 1;
}
int i10 = i3;
int i11 = 0;
while (true) {
int i12 = i9 - 1;
if (i9 <= 0) {
break;
}
i11 = scipOverNewLine(bArr, i11);
i9 = i12;
}
if (i11 >= remaining - 4) {
throw new ResponseException(Response.Status.INTERNAL_ERROR, "Multipart header size exceeds MAX_HEADER_SIZE.");
}
int i13 = boundaryPositions[i6] + i11;
i6++;
int i14 = boundaryPositions[i6] - 4;
byteBuffer.position(i13);
List<String> list = map.get(str);
if (list == null) {
list = new ArrayList<>();
map.put(str, list);
}
if (str3 == null) {
byte[] bArr2 = new byte[i14 - i13];
byteBuffer.get(bArr2);
list.add(new String(bArr2, contentType.getEncoding()));
} else {
String saveTmpFile = saveTmpFile(byteBuffer, i13, i14 - i13, str2);
if (map2.containsKey(str)) {
int i15 = i10;
while (true) {
if (!map2.containsKey(str + i15)) {
break;
} else {
i15++;
}
}
map2.put(str + i15, saveTmpFile);
} else {
map2.put(str, saveTmpFile);
}
list.add(str2);
}
i3 = i10;
i4 = 1024;
i5 = 0;
}
throw new ResponseException(Response.Status.BAD_REQUEST, "BAD REQUEST: Content type is multipart/form-data but chunk does not start with boundary.");
} catch (ResponseException e2) {
throw e2;
} catch (Exception e3) {
throw new ResponseException(Response.Status.INTERNAL_ERROR, e3.toString());
}
}
private void decodeParms(String str, Map<String, List<String>> map) {
String trim;
String str2;
if (str == null) {
this.queryParameterString = "";
return;
}
this.queryParameterString = str;
StringTokenizer stringTokenizer = new StringTokenizer(str, "&");
while (stringTokenizer.hasMoreTokens()) {
String nextToken = stringTokenizer.nextToken();
int indexOf = nextToken.indexOf(61);
if (indexOf >= 0) {
trim = NanoHTTPD.decodePercent(nextToken.substring(0, indexOf)).trim();
str2 = NanoHTTPD.decodePercent(nextToken.substring(indexOf + 1));
} else {
trim = NanoHTTPD.decodePercent(nextToken).trim();
str2 = "";
}
List<String> list = map.get(trim);
if (list == null) {
list = new ArrayList<>();
map.put(trim, list);
}
list.add(str2);
}
}
private int findHeaderEnd(byte[] bArr, int i2) {
int i3;
int i4 = 0;
while (true) {
int i5 = i4 + 1;
if (i5 >= i2) {
return 0;
}
byte b2 = bArr[i4];
if (b2 == 13 && bArr[i5] == 10 && (i3 = i4 + 3) < i2 && bArr[i4 + 2] == 13 && bArr[i3] == 10) {
return i4 + 4;
}
if (b2 == 10 && bArr[i5] == 10) {
return i4 + 2;
}
i4 = i5;
}
}
private int[] getBoundaryPositions(ByteBuffer byteBuffer, byte[] bArr) {
int[] iArr = new int[0];
if (byteBuffer.remaining() < bArr.length) {
return iArr;
}
int length = bArr.length + 4096;
byte[] bArr2 = new byte[length];
int remaining = byteBuffer.remaining() < length ? byteBuffer.remaining() : length;
byteBuffer.get(bArr2, 0, remaining);
int length2 = remaining - bArr.length;
int i2 = 0;
do {
for (int i3 = 0; i3 < length2; i3++) {
for (int i4 = 0; i4 < bArr.length && bArr2[i3 + i4] == bArr[i4]; i4++) {
if (i4 == bArr.length - 1) {
int[] iArr2 = new int[iArr.length + 1];
System.arraycopy(iArr, 0, iArr2, 0, iArr.length);
iArr2[iArr.length] = i2 + i3;
iArr = iArr2;
}
}
}
i2 += length2;
System.arraycopy(bArr2, length - bArr.length, bArr2, 0, bArr.length);
length2 = length - bArr.length;
if (byteBuffer.remaining() < length2) {
length2 = byteBuffer.remaining();
}
byteBuffer.get(bArr2, bArr.length, length2);
} while (length2 > 0);
return iArr;
}
private RandomAccessFile getTmpBucket() {
try {
return new RandomAccessFile(this.tempFileManager.createTempFile(null).getName(), "rw");
} catch (Exception e2) {
throw new Error(e2);
}
}
private String saveTmpFile(ByteBuffer byteBuffer, int i2, int i3, String str) {
TempFile createTempFile;
ByteBuffer duplicate;
FileOutputStream fileOutputStream;
if (i3 <= 0) {
return "";
}
FileOutputStream fileOutputStream2 = null;
try {
try {
createTempFile = this.tempFileManager.createTempFile(str);
duplicate = byteBuffer.duplicate();
fileOutputStream = new FileOutputStream(createTempFile.getName());
} catch (Exception e2) {
e = e2;
}
} catch (Throwable th) {
th = th;
}
try {
FileChannel channel = fileOutputStream.getChannel();
duplicate.position(i2).limit(i2 + i3);
channel.write(duplicate.slice());
String name = createTempFile.getName();
NanoHTTPD.safeClose(fileOutputStream);
return name;
} catch (Exception e3) {
e = e3;
fileOutputStream2 = fileOutputStream;
throw new Error(e);
} catch (Throwable th2) {
th = th2;
fileOutputStream2 = fileOutputStream;
NanoHTTPD.safeClose(fileOutputStream2);
throw th;
}
}
private int scipOverNewLine(byte[] bArr, int i2) {
while (bArr[i2] != 10) {
i2++;
}
return i2 + 1;
}
@Override
public void execute() {
try {
try {
try {
try {
try {
byte[] bArr = new byte[8192];
boolean z2 = false;
this.splitbyte = 0;
this.rlen = 0;
this.inputStream.mark(8192);
try {
int read = this.inputStream.read(bArr, 0, 8192);
if (read == -1) {
NanoHTTPD.safeClose(this.inputStream);
NanoHTTPD.safeClose(this.outputStream);
throw new SocketException("NanoHttpd Shutdown");
}
while (read > 0) {
int i2 = this.rlen + read;
this.rlen = i2;
int findHeaderEnd = findHeaderEnd(bArr, i2);
this.splitbyte = findHeaderEnd;
if (findHeaderEnd > 0) {
break;
}
BufferedInputStream bufferedInputStream = this.inputStream;
int i3 = this.rlen;
read = bufferedInputStream.read(bArr, i3, 8192 - i3);
}
if (this.splitbyte < this.rlen) {
this.inputStream.reset();
this.inputStream.skip(this.splitbyte);
}
this.parms = new HashMap();
Map<String, String> map = this.headers;
if (map == null) {
this.headers = new HashMap();
} else {
map.clear();
}
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(bArr, 0, this.rlen)));
HashMap hashMap = new HashMap();
decodeHeader(bufferedReader, hashMap, this.parms, this.headers);
String str = this.remoteIp;
if (str != null) {
this.headers.put("remote-addr", str);
this.headers.put("http-client-ip", this.remoteIp);
}
Method lookup = Method.lookup((String) hashMap.get("method"));
this.method = lookup;
if (lookup == null) {
throw new ResponseException(Response.Status.BAD_REQUEST, "BAD REQUEST: Syntax error. HTTP verb " + ((String) hashMap.get("method")) + " unhandled.");
}
this.uri = (String) hashMap.get("uri");
this.cookies = NanoHTTPD.this.new CookieHandler(this.headers);
String str2 = this.headers.get("connection");
boolean z3 = "HTTP/1.1".equals(this.protocolVersion) && (str2 == null || !str2.matches("(?i).*close.*"));
Response serve = NanoHTTPD.this.serve(this);
if (serve == null) {
throw new ResponseException(Response.Status.INTERNAL_ERROR, "SERVER INTERNAL ERROR: Serve() returned a null response.");
}
String str3 = this.headers.get("accept-encoding");
this.cookies.unloadQueue(serve);
serve.setRequestMethod(this.method);
if (NanoHTTPD.this.useGzipWhenAccepted(serve) && str3 != null && str3.contains("gzip")) {
z2 = true;
}
serve.setGzipEncoding(z2);
serve.setKeepAlive(z3);
serve.send(this.outputStream);
if (!z3 || serve.isCloseConnection()) {
throw new SocketException("NanoHttpd Shutdown");
}
NanoHTTPD.safeClose(serve);
this.tempFileManager.clear();
} catch (SSLException e2) {
throw e2;
} catch (IOException unused) {
NanoHTTPD.safeClose(this.inputStream);
NanoHTTPD.safeClose(this.outputStream);
throw new SocketException("NanoHttpd Shutdown");
}
} catch (ResponseException e3) {
NanoHTTPD.newFixedLengthResponse(e3.getStatus(), NanoHTTPD.MIME_PLAINTEXT, e3.getMessage()).send(this.outputStream);
NanoHTTPD.safeClose(this.outputStream);
NanoHTTPD.safeClose(null);
this.tempFileManager.clear();
}
} catch (IOException e4) {
NanoHTTPD.newFixedLengthResponse(Response.Status.INTERNAL_ERROR, NanoHTTPD.MIME_PLAINTEXT, "SERVER INTERNAL ERROR: IOException: " + e4.getMessage()).send(this.outputStream);
NanoHTTPD.safeClose(this.outputStream);
NanoHTTPD.safeClose(null);
this.tempFileManager.clear();
}
} catch (SocketTimeoutException e5) {
throw e5;
}
} catch (SocketException e6) {
throw e6;
} catch (SSLException e7) {
NanoHTTPD.newFixedLengthResponse(Response.Status.INTERNAL_ERROR, NanoHTTPD.MIME_PLAINTEXT, "SSL PROTOCOL FAILURE: " + e7.getMessage()).send(this.outputStream);
NanoHTTPD.safeClose(this.outputStream);
NanoHTTPD.safeClose(null);
this.tempFileManager.clear();
}
} catch (Throwable th) {
NanoHTTPD.safeClose(null);
this.tempFileManager.clear();
throw th;
}
}
public long getBodySize() {
if (this.headers.containsKey("content-length")) {
return Long.parseLong(this.headers.get("content-length"));
}
if (this.splitbyte < this.rlen) {
return r1 - r0;
}
return 0L;
}
@Override
public CookieHandler getCookies() {
return this.cookies;
}
@Override
public final Map<String, String> getHeaders() {
return this.headers;
}
@Override
public final InputStream getInputStream() {
return this.inputStream;
}
@Override
public final Method getMethod() {
return this.method;
}
@Override
public final Map<String, List<String>> getParameters() {
return this.parms;
}
@Override
@Deprecated
public final Map<String, String> getParms() {
HashMap hashMap = new HashMap();
for (String str : this.parms.keySet()) {
hashMap.put(str, this.parms.get(str).get(0));
}
return hashMap;
}
@Override
public String getQueryParameterString() {
return this.queryParameterString;
}
@Override
public String getRemoteHostName() {
return this.remoteHostname;
}
@Override
public String getRemoteIpAddress() {
return this.remoteIp;
}
@Override
public final String getUri() {
return this.uri;
}
@Override
public void parseBody(Map<String, String> map) {
RandomAccessFile tmpBucket;
ByteArrayOutputStream byteArrayOutputStream;
DataOutput dataOutput;
ByteBuffer map2;
RandomAccessFile randomAccessFile = null;
try {
long bodySize = getBodySize();
if (bodySize < RealWebSocket.DEFAULT_MINIMUM_DEFLATE_SIZE) {
byteArrayOutputStream = new ByteArrayOutputStream();
dataOutput = new DataOutputStream(byteArrayOutputStream);
tmpBucket = null;
} else {
tmpBucket = getTmpBucket();
byteArrayOutputStream = null;
dataOutput = tmpBucket;
}
try {
byte[] bArr = new byte[512];
while (this.rlen >= 0 && bodySize > 0) {
int read = this.inputStream.read(bArr, 0, (int) Math.min(bodySize, 512L));
this.rlen = read;
bodySize -= read;
if (read > 0) {
dataOutput.write(bArr, 0, read);
}
}
if (byteArrayOutputStream != null) {
map2 = ByteBuffer.wrap(byteArrayOutputStream.toByteArray(), 0, byteArrayOutputStream.size());
} else {
map2 = tmpBucket.getChannel().map(FileChannel.MapMode.READ_ONLY, 0L, tmpBucket.length());
tmpBucket.seek(0L);
}
if (Method.POST.equals(this.method)) {
ContentType contentType = new ContentType(this.headers.get("content-type"));
if (!contentType.isMultipart()) {
byte[] bArr2 = new byte[map2.remaining()];
map2.get(bArr2);
String trim = new String(bArr2, contentType.getEncoding()).trim();
if ("application/x-www-form-urlencoded".equalsIgnoreCase(contentType.getContentType())) {
decodeParms(trim, this.parms);
} else if (trim.length() != 0) {
map.put("postData", trim);
}
} else {
if (contentType.getBoundary() == null) {
throw new ResponseException(Response.Status.BAD_REQUEST, "BAD REQUEST: Content type is multipart/form-data but boundary missing. Usage: GET /example/file.html");
}
decodeMultipartFormData(contentType, map2, this.parms, map);
}
} else if (Method.PUT.equals(this.method)) {
map.put("content", saveTmpFile(map2, 0, map2.limit(), null));
}
NanoHTTPD.safeClose(tmpBucket);
} catch (Throwable th) {
th = th;
randomAccessFile = tmpBucket;
NanoHTTPD.safeClose(randomAccessFile);
throw th;
}
} catch (Throwable th2) {
th = th2;
}
}
public HTTPSession(TempFileManager tempFileManager, InputStream inputStream, OutputStream outputStream, InetAddress inetAddress) {
this.tempFileManager = tempFileManager;
this.inputStream = new BufferedInputStream(inputStream, 8192);
this.outputStream = outputStream;
this.remoteIp = (inetAddress.isLoopbackAddress() || inetAddress.isAnyLocalAddress()) ? "127.0.0.1" : inetAddress.getHostAddress().toString();
this.remoteHostname = (inetAddress.isLoopbackAddress() || inetAddress.isAnyLocalAddress()) ? "localhost" : inetAddress.getHostName().toString();
this.headers = new HashMap();
}
}
public static SSLServerSocketFactory makeSSLSocketFactory(KeyStore keyStore, KeyManagerFactory keyManagerFactory) {
try {
return makeSSLSocketFactory(keyStore, keyManagerFactory.getKeyManagers());
} catch (Exception e2) {
throw new IOException(e2.getMessage());
}
}
public static SSLServerSocketFactory makeSSLSocketFactory(String str, char[] cArr) {
try {
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
InputStream resourceAsStream = NanoHTTPD.class.getResourceAsStream(str);
if (resourceAsStream == null) {
throw new IOException("Unable to load keystore from classpath: " + str);
}
keyStore.load(resourceAsStream, cArr);
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keyStore, cArr);
return makeSSLSocketFactory(keyStore, keyManagerFactory);
} catch (Exception e2) {
throw new IOException(e2.getMessage());
}
}
@Deprecated
public Response serve(String str, Method method, Map<String, String> map, Map<String, String> map2, Map<String, String> map3) {
return newFixedLengthResponse(Response.Status.NOT_FOUND, MIME_PLAINTEXT, "Not Found");
}
public static Response newFixedLengthResponse(String str) {
return newFixedLengthResponse(Response.Status.OK, MIME_HTML, str);
}
}