2015-06-28 09:19:07 +00:00
|
|
|
package eu.siacs.conversations.http;
|
|
|
|
|
|
|
|
import android.util.Log;
|
|
|
|
|
2021-03-19 13:57:15 +00:00
|
|
|
import org.jetbrains.annotations.NotNull;
|
|
|
|
|
|
|
|
import java.io.IOException;
|
2018-02-16 10:14:16 +00:00
|
|
|
import java.util.Arrays;
|
|
|
|
import java.util.List;
|
2021-03-19 13:57:15 +00:00
|
|
|
import java.util.concurrent.TimeUnit;
|
2015-07-10 12:14:45 +00:00
|
|
|
|
2015-06-28 09:19:07 +00:00
|
|
|
import eu.siacs.conversations.Config;
|
|
|
|
import eu.siacs.conversations.entities.Account;
|
|
|
|
import eu.siacs.conversations.entities.DownloadableFile;
|
|
|
|
import eu.siacs.conversations.entities.Message;
|
2015-07-20 12:26:29 +00:00
|
|
|
import eu.siacs.conversations.entities.Transferable;
|
2015-07-31 23:19:16 +00:00
|
|
|
import eu.siacs.conversations.services.AbstractConnectionManager;
|
2015-06-28 09:19:07 +00:00
|
|
|
import eu.siacs.conversations.services.XmppConnectionService;
|
2015-06-29 00:04:58 +00:00
|
|
|
import eu.siacs.conversations.utils.CryptoHelper;
|
2021-03-19 13:57:15 +00:00
|
|
|
import okhttp3.Call;
|
|
|
|
import okhttp3.Callback;
|
|
|
|
import okhttp3.OkHttpClient;
|
|
|
|
import okhttp3.Request;
|
|
|
|
import okhttp3.RequestBody;
|
|
|
|
import okhttp3.Response;
|
|
|
|
|
|
|
|
public class HttpUploadConnection implements Transferable, AbstractConnectionManager.ProgressListener {
|
|
|
|
|
|
|
|
static final List<String> WHITE_LISTED_HEADERS = Arrays.asList(
|
|
|
|
"Authorization",
|
|
|
|
"Cookie",
|
|
|
|
"Expires"
|
|
|
|
);
|
|
|
|
|
|
|
|
private final HttpConnectionManager mHttpConnectionManager;
|
|
|
|
private final XmppConnectionService mXmppConnectionService;
|
|
|
|
private final SlotRequester mSlotRequester;
|
|
|
|
private final Method method;
|
|
|
|
private final boolean mUseTor;
|
|
|
|
private boolean delayed = false;
|
|
|
|
private DownloadableFile file;
|
|
|
|
private final Message message;
|
|
|
|
private String mime;
|
|
|
|
private SlotRequester.Slot slot;
|
|
|
|
private byte[] key = null;
|
|
|
|
|
|
|
|
private long transmitted = 0;
|
|
|
|
private Call mostRecentCall;
|
|
|
|
|
|
|
|
public HttpUploadConnection(Message message, Method method, HttpConnectionManager httpConnectionManager) {
|
|
|
|
this.message = message;
|
|
|
|
this.method = method;
|
|
|
|
this.mHttpConnectionManager = httpConnectionManager;
|
|
|
|
this.mXmppConnectionService = httpConnectionManager.getXmppConnectionService();
|
|
|
|
this.mSlotRequester = new SlotRequester(this.mXmppConnectionService);
|
|
|
|
this.mUseTor = mXmppConnectionService.useTorToConnect();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean start() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int getStatus() {
|
|
|
|
return STATUS_UPLOADING;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public long getFileSize() {
|
|
|
|
return file == null ? 0 : file.getExpectedSize();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public int getProgress() {
|
|
|
|
if (file == null) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return (int) ((((double) transmitted) / file.getExpectedSize()) * 100);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void cancel() {
|
|
|
|
final Call call = this.mostRecentCall;
|
|
|
|
if (call != null && !call.isCanceled()) {
|
|
|
|
call.cancel();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void fail(String errorMessage) {
|
|
|
|
finish();
|
|
|
|
final Call call = this.mostRecentCall;
|
|
|
|
final boolean cancelled = call != null && call.isCanceled();
|
|
|
|
mXmppConnectionService.markMessage(message, Message.STATUS_SEND_FAILED, cancelled ? Message.ERROR_MESSAGE_CANCELLED : errorMessage);
|
|
|
|
}
|
|
|
|
|
|
|
|
private void finish() {
|
|
|
|
mHttpConnectionManager.finishUploadConnection(this);
|
|
|
|
message.setTransferable(null);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void init(boolean delay) {
|
|
|
|
final Account account = message.getConversation().getAccount();
|
|
|
|
this.file = mXmppConnectionService.getFileBackend().getFile(message, false);
|
|
|
|
if (message.getEncryption() == Message.ENCRYPTION_PGP || message.getEncryption() == Message.ENCRYPTION_DECRYPTED) {
|
|
|
|
this.mime = "application/pgp-encrypted";
|
|
|
|
} else {
|
|
|
|
this.mime = this.file.getMimeType();
|
|
|
|
}
|
|
|
|
final long originalFileSize = file.getSize();
|
|
|
|
this.delayed = delay;
|
|
|
|
if (Config.ENCRYPT_ON_HTTP_UPLOADED
|
|
|
|
|| message.getEncryption() == Message.ENCRYPTION_AXOLOTL
|
|
|
|
|| message.getEncryption() == Message.ENCRYPTION_OTR) {
|
|
|
|
this.key = new byte[44];
|
|
|
|
mXmppConnectionService.getRNG().nextBytes(this.key);
|
|
|
|
this.file.setKeyAndIv(this.key);
|
|
|
|
}
|
|
|
|
this.file.setExpectedSize(originalFileSize + (file.getKey() != null ? 16 : 0));
|
|
|
|
message.resetFileParams();
|
|
|
|
this.mSlotRequester.request(method, account, file, mime, new SlotRequester.OnSlotRequested() {
|
|
|
|
@Override
|
|
|
|
public void success(final SlotRequester.Slot slot) {
|
|
|
|
//TODO needs to mark the message as cancelled afterwards (ie call fail())
|
|
|
|
HttpUploadConnection.this.slot = slot;
|
|
|
|
HttpUploadConnection.this.upload();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void failure(String message) {
|
|
|
|
fail(message);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
message.setTransferable(this);
|
|
|
|
mXmppConnectionService.markMessage(message, Message.STATUS_UNSEND);
|
|
|
|
}
|
|
|
|
|
|
|
|
private void upload() {
|
|
|
|
final OkHttpClient client = mHttpConnectionManager.buildHttpClient(
|
|
|
|
slot.put,
|
|
|
|
message.getConversation().getAccount(),
|
|
|
|
true
|
|
|
|
);
|
|
|
|
final RequestBody requestBody = AbstractConnectionManager.requestBody(file, this);
|
|
|
|
final Request request = new Request.Builder()
|
|
|
|
.url(slot.put)
|
|
|
|
.put(requestBody)
|
|
|
|
.headers(slot.headers)
|
|
|
|
.build();
|
|
|
|
Log.d(Config.LOGTAG, "uploading file to " + slot.put);
|
|
|
|
this.mostRecentCall = client.newCall(request);
|
|
|
|
this.mostRecentCall.enqueue(new Callback() {
|
|
|
|
@Override
|
|
|
|
public void onFailure(@NotNull Call call, IOException e) {
|
|
|
|
Log.d(Config.LOGTAG, "http upload failed", e);
|
|
|
|
fail(e.getMessage());
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
|
|
|
|
final int code = response.code();
|
|
|
|
if (code == 200 || code == 201) {
|
|
|
|
Log.d(Config.LOGTAG, "finished uploading file");
|
|
|
|
final String get;
|
|
|
|
if (key != null) {
|
|
|
|
get = AesGcmURL.toAesGcmUrl(slot.get.newBuilder().fragment(CryptoHelper.bytesToHex(key)).build());
|
|
|
|
} else {
|
|
|
|
get = slot.get.toString();
|
|
|
|
}
|
|
|
|
mXmppConnectionService.getFileBackend().updateFileParams(message, get);
|
|
|
|
mXmppConnectionService.getFileBackend().updateMediaScanner(file);
|
|
|
|
finish();
|
|
|
|
if (!message.isPrivateMessage()) {
|
|
|
|
message.setCounterpart(message.getConversation().getJid().asBareJid());
|
|
|
|
}
|
|
|
|
mXmppConnectionService.resendMessage(message, delayed);
|
|
|
|
} else {
|
|
|
|
Log.d(Config.LOGTAG, "http upload failed because response code was " + code);
|
|
|
|
fail("http upload failed because response code was " + code);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
public Message getMessage() {
|
|
|
|
return message;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onProgress(final long progress) {
|
|
|
|
this.transmitted = progress;
|
|
|
|
mHttpConnectionManager.updateConversationUi(false);
|
|
|
|
}
|
|
|
|
}
|