Session v1.18.2版本的 MD5 值为:92ce129e957021e1a845dcaca5ce957d

以下内容为反编译后的 AttachmentServer.java 源代码,内容仅作参考


package org.thoughtcrime.securesms.attachments;

import android.content.Context;
import android.net.Uri;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.security.MessageDigest;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.StringTokenizer;
import org.apache.http.conn.ssl.TokenParser;
import org.session.libsession.messaging.sending_receiving.attachments.Attachment;
import org.session.libsession.utilities.Util;
import org.session.libsignal.utilities.Hex;
import org.session.libsignal.utilities.Log;
import org.thoughtcrime.securesms.mms.PartAuthority;

public class AttachmentServer implements Runnable {
    private static final String TAG = "AttachmentServer";
    private final Attachment attachment;
    private final String auth;
    private final Context context;
    private volatile boolean isRunning;
    private final int port;
    private final ServerSocket socket;

    public AttachmentServer(Context context, Attachment attachment) throws IOException {
        try {
            this.context = context;
            this.attachment = attachment;
            ServerSocket serverSocket = new ServerSocket(0, 0, InetAddress.getByAddress(new byte[]{Byte.MAX_VALUE, 0, 0, 1}));
            this.socket = serverSocket;
            this.port = serverSocket.getLocalPort();
            this.auth = Hex.toStringCondensed(Util.getSecretBytes(16));
            serverSocket.setSoTimeout(5000);
        } catch (UnknownHostException e) {
            throw new AssertionError(e);
        }
    }

    public Uri getUri() {
        return Uri.parse(String.format(Locale.ROOT, "http://127.0.0.1:%d/%s", Integer.valueOf(this.port), this.auth));
    }

    public void start() {
        this.isRunning = true;
        new Thread(this).start();
    }

    public void stop() {
        this.isRunning = false;
    }

    @Override
    public void run() {
        while (this.isRunning) {
            Socket socket = null;
            try {
                try {
                    try {
                        socket = this.socket.accept();
                        if (socket != null) {
                            StreamToMediaPlayerTask streamToMediaPlayerTask = new StreamToMediaPlayerTask(socket, "/" + this.auth);
                            if (streamToMediaPlayerTask.processRequest()) {
                                streamToMediaPlayerTask.execute();
                            }
                        }
                    } catch (IOException e) {
                        Log.e(TAG, "Error connecting to client", e);
                        if (socket != null) {
                        }
                    }
                } catch (SocketTimeoutException e2) {
                    Log.w(TAG, e2);
                    if (socket == null) {
                    }
                }
                if (socket == null) {
                }
                try {
                    socket.close();
                } catch (IOException unused) {
                }
            } catch (Throwable th) {
                if (socket != null) {
                    try {
                        socket.close();
                    } catch (IOException unused2) {
                    }
                }
                throw th;
            }
        }
        Log.d(TAG, "Proxy interrupted. Shutting down.");
    }

    private class StreamToMediaPlayerTask {
        private final String auth;
        private long cbSkip;
        private final Socket client;
        private Properties parameters;
        private Properties request;
        private Properties requestHeaders;

        public StreamToMediaPlayerTask(Socket socket, String str) {
            this.client = socket;
            this.auth = str;
        }

        public boolean processRequest() throws IOException {
            InputStream inputStream = this.client.getInputStream();
            byte[] bArr = new byte[8192];
            int read = inputStream.read(bArr, 0, 8192);
            int i = 0;
            while (read > 0) {
                i += read;
                if (findHeaderEnd(bArr, i) > 0) {
                    break;
                }
                read = inputStream.read(bArr, i, 8192 - i);
            }
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(bArr, 0, i)));
            this.request = new Properties();
            this.parameters = new Properties();
            Properties properties = new Properties();
            this.requestHeaders = properties;
            try {
                decodeHeader(bufferedReader, this.request, this.parameters, properties);
            } catch (InterruptedException e) {
                Log.e(AttachmentServer.TAG, "Exception: " + e.getMessage());
                e.printStackTrace();
            }
            for (Map.Entry entry : this.requestHeaders.entrySet()) {
                Log.i(AttachmentServer.TAG, "Header: " + entry.getKey() + " : " + entry.getValue());
            }
            String property = this.requestHeaders.getProperty("range");
            if (property != null) {
                Log.i(AttachmentServer.TAG, "range is: " + property);
                String substring = property.substring(6);
                int indexOf = substring.indexOf(45);
                if (indexOf > 0) {
                    substring = substring.substring(0, indexOf);
                }
                this.cbSkip = Long.parseLong(substring);
                Log.i(AttachmentServer.TAG, "range found!! " + this.cbSkip);
            }
            if (!"GET".equals(this.request.get("method"))) {
                Log.e(AttachmentServer.TAG, "Only GET is supported: " + this.request.get("method"));
                return false;
            }
            String property2 = this.request.getProperty("uri");
            if (property2 != null && MessageDigest.isEqual(property2.getBytes(), this.auth.getBytes())) {
                return true;
            }
            Log.w(AttachmentServer.TAG, "Bad auth token!");
            return false;
        }

        protected void execute() throws IOException {
            String str;
            BufferedOutputStream bufferedOutputStream;
            int read;
            InputStream attachmentStream = PartAuthority.getAttachmentStream(AttachmentServer.this.context, AttachmentServer.this.attachment.getDataUri());
            long size = AttachmentServer.this.attachment.getSize();
            if (this.cbSkip > 0) {
                str = ((((("HTTP/1.1 206 Partial Content\r\nContent-Type: " + AttachmentServer.this.attachment.getContentType() + "\r\n") + "Accept-Ranges: bytes\r\n") + "Content-Length: " + (size - this.cbSkip) + "\r\n") + "Content-Range: bytes " + this.cbSkip + "-" + (size - 1) + "/" + size + "\r\n") + "Connection: Keep-Alive\r\n") + "\r\n";
            } else {
                str = (((("HTTP/1.1 200 OK\r\nContent-Type: " + AttachmentServer.this.attachment.getContentType() + "\r\n") + "Accept-Ranges: bytes\r\n") + "Content-Length: " + size + "\r\n") + "Connection: Keep-Alive\r\n") + "\r\n";
            }
            Log.i(AttachmentServer.TAG, "headers: " + str);
            BufferedOutputStream bufferedOutputStream2 = null;
            byte[] bArr = new byte[65536];
            try {
                bufferedOutputStream = new BufferedOutputStream(this.client.getOutputStream(), 32768);
                try {
                    bufferedOutputStream.write(str.getBytes());
                    attachmentStream.skip(this.cbSkip);
                    while (!this.client.isClosed() && (read = attachmentStream.read(bArr, 0, 65536)) != -1) {
                        bufferedOutputStream.write(bArr, 0, read);
                    }
                } catch (SocketException unused) {
                    bufferedOutputStream2 = bufferedOutputStream;
                    Log.e(AttachmentServer.TAG, "SocketException() thrown, proxy client has probably closed. This can exit harmlessly");
                    bufferedOutputStream = bufferedOutputStream2;
                    if (bufferedOutputStream != null) {
                    }
                    this.client.close();
                } catch (Exception e) {
                    e = e;
                    bufferedOutputStream2 = bufferedOutputStream;
                    Log.e(AttachmentServer.TAG, "Exception thrown from streaming task:");
                    Log.e(AttachmentServer.TAG, e.getClass().getName() + " : " + e.getLocalizedMessage());
                    bufferedOutputStream = bufferedOutputStream2;
                    if (bufferedOutputStream != null) {
                    }
                    this.client.close();
                }
            } catch (SocketException unused2) {
            } catch (Exception e2) {
                e = e2;
            }
            if (bufferedOutputStream != null) {
                try {
                    bufferedOutputStream.close();
                } catch (IOException e3) {
                    Log.e(AttachmentServer.TAG, "IOException while cleaning up streaming task:");
                    Log.e(AttachmentServer.TAG, e3.getClass().getName() + " : " + e3.getLocalizedMessage());
                    e3.printStackTrace();
                    return;
                }
            }
            this.client.close();
        }

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

        private void decodeHeader(BufferedReader bufferedReader, Properties properties, Properties properties2, Properties properties3) throws InterruptedException {
            String decodePercent;
            try {
                String readLine = bufferedReader.readLine();
                if (readLine == null) {
                    return;
                }
                StringTokenizer stringTokenizer = new StringTokenizer(readLine);
                if (!stringTokenizer.hasMoreTokens()) {
                    Log.e(AttachmentServer.TAG, "BAD REQUEST: Syntax error. Usage: GET /example/file.html");
                }
                properties.put("method", stringTokenizer.nextToken());
                if (!stringTokenizer.hasMoreTokens()) {
                    Log.e(AttachmentServer.TAG, "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), properties2);
                    decodePercent = decodePercent(nextToken.substring(0, indexOf));
                } else {
                    decodePercent = decodePercent(nextToken);
                }
                if (stringTokenizer.hasMoreTokens()) {
                    String readLine2 = bufferedReader.readLine();
                    while (readLine2 != null && readLine2.trim().length() > 0) {
                        int indexOf2 = readLine2.indexOf(58);
                        if (indexOf2 >= 0) {
                            properties3.put(readLine2.substring(0, indexOf2).trim().toLowerCase(), readLine2.substring(indexOf2 + 1).trim());
                        }
                        readLine2 = bufferedReader.readLine();
                    }
                }
                properties.put("uri", decodePercent);
            } catch (IOException e) {
                Log.e(AttachmentServer.TAG, "SERVER INTERNAL ERROR: IOException: " + e.getMessage());
            }
        }

        private void decodeParms(String str, Properties properties) throws InterruptedException {
            if (str == null) {
                return;
            }
            StringTokenizer stringTokenizer = new StringTokenizer(str, "&");
            while (stringTokenizer.hasMoreTokens()) {
                String nextToken = stringTokenizer.nextToken();
                int indexOf = nextToken.indexOf(61);
                if (indexOf >= 0) {
                    properties.put(decodePercent(nextToken.substring(0, indexOf)).trim(), decodePercent(nextToken.substring(indexOf + 1)));
                }
            }
        }

        private String decodePercent(String str) throws InterruptedException {
            try {
                StringBuffer stringBuffer = new StringBuffer();
                int i = 0;
                while (i < str.length()) {
                    char charAt = str.charAt(i);
                    if (charAt == '%') {
                        stringBuffer.append((char) Integer.parseInt(str.substring(i + 1, i + 3), 16));
                        i += 2;
                    } else if (charAt == '+') {
                        stringBuffer.append(TokenParser.SP);
                    } else {
                        stringBuffer.append(charAt);
                    }
                    i++;
                }
                return stringBuffer.toString();
            } catch (Exception unused) {
                Log.e(AttachmentServer.TAG, "BAD REQUEST: Bad percent-encoding.");
                return null;
            }
        }
    }
}