导航菜单

页面标题

页面副标题

St.John's v1.0.9 - HTTPSession.java 源代码

正在查看: St.John's v1.0.9 应用的 HTTPSession.java JAVA 源代码文件

本页面展示 JAVA 反编译生成的源代码文件,支持语法高亮显示。 仅供安全研究与技术分析使用,严禁用于任何非法用途。请遵守相关法律法规。


package org.nanohttpd.protocols.http;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataOutput;
import java.io.DataOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.logging.Level;
import java.util.regex.Matcher;
import javax.net.ssl.SSLException;
import org.ccil.cowan.tagsoup.XMLWriter;
import org.nanohttpd.protocols.http.NanoHTTPD;
import org.nanohttpd.protocols.http.content.ContentType;
import org.nanohttpd.protocols.http.content.CookieHandler;
import org.nanohttpd.protocols.http.request.Method;
import org.nanohttpd.protocols.http.response.Response;
import org.nanohttpd.protocols.http.response.Status;
import org.nanohttpd.protocols.http.tempfiles.ITempFile;
import org.nanohttpd.protocols.http.tempfiles.ITempFileManager;
import org.springframework.util.MimeTypeUtils;

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;
    public static final String POST_DATA = "postData";
    private static final int REQUEST_BUFFER_LEN = 512;
    private CookieHandler cookies;
    private Map<String, String> headers;
    private final NanoHTTPD httpd;
    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 ITempFileManager tempFileManager;
    private String uri;

    public HTTPSession(NanoHTTPD nanoHTTPD, ITempFileManager iTempFileManager, InputStream inputStream, OutputStream outputStream) {
        this.httpd = nanoHTTPD;
        this.tempFileManager = iTempFileManager;
        this.inputStream = new BufferedInputStream(inputStream, 8192);
        this.outputStream = outputStream;
    }

    public HTTPSession(NanoHTTPD nanoHTTPD, ITempFileManager iTempFileManager, InputStream inputStream, OutputStream outputStream, InetAddress inetAddress) {
        this.httpd = nanoHTTPD;
        this.tempFileManager = iTempFileManager;
        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();
    }

    private void decodeHeader(BufferedReader bufferedReader, Map<String, String> map, Map<String, List<String>> map2, Map<String, String> map3) throws NanoHTTPD.ResponseException {
        String decodePercent;
        try {
            String readLine = bufferedReader.readLine();
            if (readLine == null) {
                return;
            }
            StringTokenizer stringTokenizer = new StringTokenizer(readLine);
            if (!stringTokenizer.hasMoreTokens()) {
                throw new NanoHTTPD.ResponseException(Status.BAD_REQUEST, "BAD REQUEST: Syntax error. Usage: GET /example/file.html");
            }
            map.put(XMLWriter.METHOD, stringTokenizer.nextToken());
            if (!stringTokenizer.hasMoreTokens()) {
                throw new NanoHTTPD.ResponseException(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 e) {
            throw new NanoHTTPD.ResponseException(Status.INTERNAL_ERROR, "SERVER INTERNAL ERROR: IOException: " + e.getMessage(), e);
        }
    }

    private void decodeMultipartFormData(ContentType contentType, ByteBuffer byteBuffer, Map<String, List<String>> map, Map<String, String> map2) throws NanoHTTPD.ResponseException {
        String str;
        try {
            int[] boundaryPositions = getBoundaryPositions(byteBuffer, contentType.getBoundary().getBytes());
            int i = 2;
            if (boundaryPositions.length < 2) {
                throw new NanoHTTPD.ResponseException(Status.BAD_REQUEST, "BAD REQUEST: Content type is multipart/form-data but contains less than two boundary strings.");
            }
            int i2 = 1024;
            byte[] bArr = new byte[1024];
            int i3 = 0;
            int i4 = 0;
            int i5 = 0;
            while (true) {
                int i6 = 1;
                if (i4 >= boundaryPositions.length - 1) {
                    return;
                }
                byteBuffer.position(boundaryPositions[i4]);
                int remaining = byteBuffer.remaining() < i2 ? byteBuffer.remaining() : 1024;
                byteBuffer.get(bArr, i3, remaining);
                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(bArr, i3, remaining), Charset.forName(contentType.getEncoding())), remaining);
                String readLine = bufferedReader.readLine();
                if (readLine == null || !readLine.contains(contentType.getBoundary())) {
                    break;
                }
                String readLine2 = bufferedReader.readLine();
                String str2 = null;
                String str3 = null;
                String str4 = null;
                int i7 = 2;
                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(i));
                        while (matcher2.find()) {
                            String group = matcher2.group(i6);
                            if ("name".equalsIgnoreCase(group)) {
                                str = matcher2.group(2);
                            } else {
                                if ("filename".equalsIgnoreCase(group)) {
                                    String group2 = matcher2.group(2);
                                    if (!group2.isEmpty()) {
                                        if (i5 > 0) {
                                            str = str2 + String.valueOf(i5);
                                            str3 = group2;
                                            i5++;
                                        } else {
                                            i5++;
                                        }
                                    }
                                    str3 = group2;
                                }
                                i6 = 1;
                            }
                            str2 = str;
                            i6 = 1;
                        }
                    }
                    Matcher matcher3 = NanoHTTPD.CONTENT_TYPE_PATTERN.matcher(readLine2);
                    if (matcher3.matches()) {
                        str4 = matcher3.group(2).trim();
                    }
                    readLine2 = bufferedReader.readLine();
                    i7++;
                    i = 2;
                    i6 = 1;
                }
                int i8 = 0;
                while (true) {
                    int i9 = i7 - 1;
                    if (i7 <= 0) {
                        break;
                    }
                    i8 = scipOverNewLine(bArr, i8);
                    i7 = i9;
                }
                if (i8 >= remaining - 4) {
                    throw new NanoHTTPD.ResponseException(Status.INTERNAL_ERROR, "Multipart header size exceeds MAX_HEADER_SIZE.");
                }
                int i10 = boundaryPositions[i4] + i8;
                i4++;
                int i11 = boundaryPositions[i4] - 4;
                byteBuffer.position(i10);
                List<String> list = map.get(str2);
                if (list == null) {
                    list = new ArrayList<>();
                    map.put(str2, list);
                }
                if (str4 == null) {
                    byte[] bArr2 = new byte[i11 - i10];
                    byteBuffer.get(bArr2);
                    list.add(new String(bArr2, contentType.getEncoding()));
                } else {
                    String saveTmpFile = saveTmpFile(byteBuffer, i10, i11 - i10, str3);
                    if (!map2.containsKey(str2)) {
                        map2.put(str2, saveTmpFile);
                    } else {
                        int i12 = 2;
                        while (true) {
                            if (!map2.containsKey(str2 + i12)) {
                                break;
                            } else {
                                i12++;
                            }
                        }
                        map2.put(str2 + i12, saveTmpFile);
                    }
                    list.add(str3);
                }
                i2 = 1024;
                i = 2;
                i3 = 0;
            }
            throw new NanoHTTPD.ResponseException(Status.BAD_REQUEST, "BAD REQUEST: Content type is multipart/form-data but chunk does not start with boundary.");
        } catch (NanoHTTPD.ResponseException e) {
            throw e;
        } catch (Exception e2) {
            throw new NanoHTTPD.ResponseException(Status.INTERNAL_ERROR, e2.toString());
        }
    }

    private int scipOverNewLine(byte[] bArr, int i) {
        while (bArr[i] != 10) {
            i++;
        }
        return i + 1;
    }

    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);
        }
    }

    @Override
    public void execute() throws IOException {
        byte[] bArr;
        Response response = null;
        try {
            try {
                try {
                    try {
                        bArr = new byte[8192];
                        this.splitbyte = 0;
                        this.rlen = 0;
                        this.inputStream.mark(8192);
                    } catch (NanoHTTPD.ResponseException e) {
                        Response.newFixedLengthResponse(e.getStatus(), "text/plain", e.getMessage()).send(this.outputStream);
                        NanoHTTPD.safeClose(this.outputStream);
                    }
                } catch (SSLException e2) {
                    Response.newFixedLengthResponse(Status.INTERNAL_ERROR, "text/plain", "SSL PROTOCOL FAILURE: " + e2.getMessage()).send(this.outputStream);
                    NanoHTTPD.safeClose(this.outputStream);
                } catch (IOException e3) {
                    Response.newFixedLengthResponse(Status.INTERNAL_ERROR, "text/plain", "SERVER INTERNAL ERROR: IOException: " + e3.getMessage()).send(this.outputStream);
                    NanoHTTPD.safeClose(this.outputStream);
                }
                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 i = this.rlen + read;
                        this.rlen = i;
                        int findHeaderEnd = findHeaderEnd(bArr, i);
                        this.splitbyte = findHeaderEnd;
                        if (findHeaderEnd > 0) {
                            break;
                        }
                        BufferedInputStream bufferedInputStream = this.inputStream;
                        int i2 = this.rlen;
                        read = bufferedInputStream.read(bArr, i2, 8192 - i2);
                    }
                    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(hashMap.get(XMLWriter.METHOD));
                    this.method = lookup;
                    if (lookup == null) {
                        throw new NanoHTTPD.ResponseException(Status.BAD_REQUEST, "BAD REQUEST: Syntax error. HTTP verb " + hashMap.get(XMLWriter.METHOD) + " unhandled.");
                    }
                    this.uri = hashMap.get("uri");
                    this.cookies = new CookieHandler(this.headers);
                    String str2 = this.headers.get("connection");
                    boolean z = "HTTP/1.1".equals(this.protocolVersion) && (str2 == null || !str2.matches("(?i).*close.*"));
                    response = this.httpd.handle(this);
                    if (response == null) {
                        throw new NanoHTTPD.ResponseException(Status.INTERNAL_ERROR, "SERVER INTERNAL ERROR: Serve() returned a null response.");
                    }
                    String str3 = this.headers.get("accept-encoding");
                    this.cookies.unloadQueue(response);
                    response.setRequestMethod(this.method);
                    if (str3 == null || !str3.contains("gzip")) {
                        response.setUseGzip(false);
                    }
                    response.setKeepAlive(z);
                    response.send(this.outputStream);
                    if (!z || response.isCloseConnection()) {
                        throw new SocketException("NanoHttpd Shutdown");
                    }
                } catch (SSLException e4) {
                    throw e4;
                } catch (IOException unused) {
                    NanoHTTPD.safeClose(this.inputStream);
                    NanoHTTPD.safeClose(this.outputStream);
                    throw new SocketException("NanoHttpd Shutdown");
                }
            } catch (SocketException e5) {
                throw e5;
            } catch (SocketTimeoutException e6) {
                throw e6;
            }
        } finally {
            NanoHTTPD.safeClose(null);
            this.tempFileManager.clear();
        }
    }

    private int findHeaderEnd(byte[] bArr, int i) {
        int i2;
        int i3 = 0;
        while (true) {
            int i4 = i3 + 1;
            if (i4 >= i) {
                return 0;
            }
            byte b = bArr[i3];
            if (b == 13 && bArr[i4] == 10 && (i2 = i3 + 3) < i && bArr[i3 + 2] == 13 && bArr[i2] == 10) {
                return i3 + 4;
            }
            if (b == 10 && bArr[i4] == 10) {
                return i3 + 2;
            }
            i3 = i4;
        }
    }

    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 i = 0;
        do {
            for (int i2 = 0; i2 < length2; i2++) {
                for (int i3 = 0; i3 < bArr.length && bArr2[i2 + i3] == bArr[i3]; i3++) {
                    if (i3 == bArr.length - 1) {
                        int[] iArr2 = new int[iArr.length + 1];
                        System.arraycopy(iArr, 0, iArr2, 0, iArr.length);
                        iArr2[iArr.length] = i + i2;
                        iArr = iArr2;
                    }
                }
            }
            i += 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;
    }

    @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
    @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 final Map<String, List<String>> getParameters() {
        return this.parms;
    }

    @Override
    public String getQueryParameterString() {
        return this.queryParameterString;
    }

    private RandomAccessFile getTmpBucket() {
        try {
            return new RandomAccessFile(this.tempFileManager.createTempFile(null).getName(), "rw");
        } catch (Exception e) {
            throw new Error(e);
        }
    }

    @Override
    public final String getUri() {
        return this.uri;
    }

    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 void parseBody(Map<String, String> map) throws IOException, NanoHTTPD.ResponseException {
        long bodySize;
        RandomAccessFile tmpBucket;
        ByteArrayOutputStream byteArrayOutputStream;
        DataOutput dataOutput;
        ByteBuffer map2;
        RandomAccessFile randomAccessFile = null;
        try {
            bodySize = getBodySize();
            if (bodySize < 1024) {
                byteArrayOutputStream = new ByteArrayOutputStream();
                dataOutput = new DataOutputStream(byteArrayOutputStream);
                tmpBucket = null;
            } else {
                tmpBucket = getTmpBucket();
                byteArrayOutputStream = null;
                dataOutput = tmpBucket;
            }
        } catch (Throwable th) {
            th = th;
        }
        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()) {
                    if (contentType.getBoundary() == null) {
                        throw new NanoHTTPD.ResponseException(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 {
                    byte[] bArr2 = new byte[map2.remaining()];
                    map2.get(bArr2);
                    String trim = new String(bArr2, contentType.getEncoding()).trim();
                    if (MimeTypeUtils.APPLICATION_FORM_URLENCODED_VALUE.equalsIgnoreCase(contentType.getContentType())) {
                        decodeParms(trim, this.parms);
                    } else if (trim.length() != 0) {
                        map.put(POST_DATA, trim);
                    }
                }
            } else if (Method.PUT.equals(this.method)) {
                map.put("content", saveTmpFile(map2, 0, map2.limit(), null));
            }
            NanoHTTPD.safeClose(tmpBucket);
        } catch (Throwable th2) {
            th = th2;
            randomAccessFile = tmpBucket;
            NanoHTTPD.safeClose(randomAccessFile);
            throw th;
        }
    }

    private String saveTmpFile(ByteBuffer byteBuffer, int i, int i2, String str) {
        ITempFile createTempFile;
        ByteBuffer duplicate;
        FileOutputStream fileOutputStream;
        if (i2 <= 0) {
            return "";
        }
        FileOutputStream fileOutputStream2 = null;
        try {
            try {
                createTempFile = this.tempFileManager.createTempFile(str);
                duplicate = byteBuffer.duplicate();
                fileOutputStream = new FileOutputStream(createTempFile.getName());
            } catch (Exception e) {
                e = e;
            }
        } catch (Throwable th) {
            th = th;
        }
        try {
            FileChannel channel = fileOutputStream.getChannel();
            duplicate.position(i).limit(i + i2);
            channel.write(duplicate.slice());
            String name = createTempFile.getName();
            NanoHTTPD.safeClose(fileOutputStream);
            return name;
        } catch (Exception e2) {
            e = e2;
            fileOutputStream2 = fileOutputStream;
            throw new Error(e);
        } catch (Throwable th2) {
            th = th2;
            fileOutputStream2 = fileOutputStream;
            NanoHTTPD.safeClose(fileOutputStream2);
            throw th;
        }
    }

    @Override
    public String getRemoteIpAddress() {
        return this.remoteIp;
    }

    @Override
    public String getRemoteHostName() {
        return this.remoteHostname;
    }
}