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