handle p1s3 urls in http downloader

This commit is contained in:
Daniel Gultsch 2018-05-25 15:37:14 +02:00
parent 4626bdf8d8
commit ea5cdec186
3 changed files with 134 additions and 64 deletions

View file

@ -276,6 +276,7 @@ public class IqGenerator extends AbstractGenerator {
set.addChild("max").setContent(String.valueOf(Config.PAGE_SIZE)); set.addChild("max").setContent(String.valueOf(Config.PAGE_SIZE));
return packet; return packet;
} }
public IqPacket generateGetBlockList() { public IqPacket generateGetBlockList() {
final IqPacket iq = new IqPacket(IqPacket.TYPE.GET); final IqPacket iq = new IqPacket(IqPacket.TYPE.GET);
iq.addChild("blocklist", Namespace.BLOCKING); iq.addChild("blocklist", Namespace.BLOCKING);
@ -354,7 +355,13 @@ public class IqGenerator extends AbstractGenerator {
IqPacket packet = new IqPacket(IqPacket.TYPE.SET); IqPacket packet = new IqPacket(IqPacket.TYPE.SET);
packet.setTo(host); packet.setTo(host);
packet.query(Namespace.P1_S3_FILE_TRANSFER).setAttribute("md5", md5); packet.query(Namespace.P1_S3_FILE_TRANSFER).setAttribute("md5", md5);
Log.d(Config.LOGTAG,packet.toString()); return packet;
}
public IqPacket requestP1S3Url(Jid host, String fileId) {
IqPacket packet = new IqPacket(IqPacket.TYPE.GET);
packet.setTo(host);
packet.query(Namespace.P1_S3_FILE_TRANSFER).setAttribute("fileid", fileId);
return packet; return packet;
} }

View file

@ -106,7 +106,8 @@ public class MessageGenerator extends AbstractGenerator {
final URL url = fileParams.url; final URL url = fileParams.url;
if (P1S3UrlStreamHandler.PROTOCOL_NAME.equals(url.getProtocol())) { if (P1S3UrlStreamHandler.PROTOCOL_NAME.equals(url.getProtocol())) {
Element x = packet.addChild("x", Namespace.P1_S3_FILE_TRANSFER); Element x = packet.addChild("x", Namespace.P1_S3_FILE_TRANSFER);
x.setAttribute("name", url.getFile()); final String file = url.getFile();
x.setAttribute("name", file.charAt(0) == '/' ? file.substring(1) : file);
x.setAttribute("fileid", url.getHost()); x.setAttribute("fileid", url.getHost());
return packet; return packet;
} else { } else {
@ -127,7 +128,8 @@ public class MessageGenerator extends AbstractGenerator {
final URL url = fileParams.url; final URL url = fileParams.url;
if (P1S3UrlStreamHandler.PROTOCOL_NAME.equals(url.getProtocol())) { if (P1S3UrlStreamHandler.PROTOCOL_NAME.equals(url.getProtocol())) {
Element x = packet.addChild("x", Namespace.P1_S3_FILE_TRANSFER); Element x = packet.addChild("x", Namespace.P1_S3_FILE_TRANSFER);
x.setAttribute("name", url.getFile()); final String file = url.getFile();
x.setAttribute("name", file.charAt(0) == '/' ? file.substring(1) : file);
x.setAttribute("fileid", url.getHost()); x.setAttribute("fileid", url.getHost());
} else { } else {
packet.setBody(url.toString()); packet.setBody(url.toString());

View file

@ -1,6 +1,7 @@
package eu.siacs.conversations.http; package eu.siacs.conversations.http;
import android.os.PowerManager; import android.os.PowerManager;
import android.support.annotation.Nullable;
import android.util.Log; import android.util.Log;
import java.io.BufferedInputStream; import java.io.BufferedInputStream;
@ -17,6 +18,7 @@ import javax.net.ssl.SSLHandshakeException;
import eu.siacs.conversations.Config; import eu.siacs.conversations.Config;
import eu.siacs.conversations.R; import eu.siacs.conversations.R;
import eu.siacs.conversations.entities.Account;
import eu.siacs.conversations.entities.DownloadableFile; import eu.siacs.conversations.entities.DownloadableFile;
import eu.siacs.conversations.entities.Message; import eu.siacs.conversations.entities.Message;
import eu.siacs.conversations.entities.Transferable; import eu.siacs.conversations.entities.Transferable;
@ -27,6 +29,9 @@ import eu.siacs.conversations.services.XmppConnectionService;
import eu.siacs.conversations.utils.CryptoHelper; import eu.siacs.conversations.utils.CryptoHelper;
import eu.siacs.conversations.utils.FileWriterException; import eu.siacs.conversations.utils.FileWriterException;
import eu.siacs.conversations.utils.WakeLockHelper; import eu.siacs.conversations.utils.WakeLockHelper;
import eu.siacs.conversations.xmpp.OnIqPacketReceived;
import eu.siacs.conversations.xmpp.stanzas.IqPacket;
import rocks.xmpp.addr.Jid;
public class HttpDownloadConnection implements Transferable { public class HttpDownloadConnection implements Transferable {
@ -39,8 +44,9 @@ public class HttpDownloadConnection implements Transferable {
private int mStatus = Transferable.STATUS_UNKNOWN; private int mStatus = Transferable.STATUS_UNKNOWN;
private boolean acceptedAutomatically = false; private boolean acceptedAutomatically = false;
private int mProgress = 0; private int mProgress = 0;
private boolean mUseTor = false; private final boolean mUseTor;
private boolean canceled = false; private boolean canceled = false;
private Method method = Method.HTTP_UPLOAD;
public HttpDownloadConnection(HttpConnectionManager manager) { public HttpDownloadConnection(HttpConnectionManager manager) {
this.mHttpConnectionManager = manager; this.mHttpConnectionManager = manager;
@ -100,6 +106,7 @@ public class HttpDownloadConnection implements Transferable {
if (this.message.getEncryption() == Message.ENCRYPTION_AXOLOTL && this.file.getKey() == null) { if (this.message.getEncryption() == Message.ENCRYPTION_AXOLOTL && this.file.getKey() == null) {
this.message.setEncryption(Message.ENCRYPTION_NONE); this.message.setEncryption(Message.ENCRYPTION_NONE);
} }
method = mUrl.getProtocol().equalsIgnoreCase(P1S3UrlStreamHandler.PROTOCOL_NAME) ? Method.P1_S3 : Method.HTTP_UPLOAD;
checkFileSize(interactive); checkFileSize(interactive);
} catch (MalformedURLException e) { } catch (MalformedURLException e) {
this.cancel(); this.cancel();
@ -153,7 +160,7 @@ public class HttpDownloadConnection implements Transferable {
} }
} }
public void updateProgress(long i) { private void updateProgress(long i) {
this.mProgress = (int) i; this.mProgress = (int) i;
mHttpConnectionManager.updateConversationUi(false); mHttpConnectionManager.updateConversationUi(false);
} }
@ -179,27 +186,64 @@ public class HttpDownloadConnection implements Transferable {
private class FileSizeChecker implements Runnable { private class FileSizeChecker implements Runnable {
private boolean interactive = false; private final boolean interactive;
public FileSizeChecker(boolean interactive) { FileSizeChecker(boolean interactive) {
this.interactive = interactive; this.interactive = interactive;
} }
@Override @Override
public void run() { public void run() {
long size; if (mUrl.getProtocol().equalsIgnoreCase(P1S3UrlStreamHandler.PROTOCOL_NAME)) {
retrieveUrl();
} else {
check();
}
}
private void retrieveUrl() {
changeStatus(STATUS_CHECKING);
final Account account = message.getConversation().getAccount();
IqPacket request = mXmppConnectionService.getIqGenerator().requestP1S3Url(Jid.of(account.getJid().getDomain()), mUrl.getHost());
mXmppConnectionService.sendIqPacket(message.getConversation().getAccount(), request, (a, packet) -> {
if (packet.getType() == IqPacket.TYPE.RESULT) {
String download = packet.query().getAttribute("download");
if (download != null) {
try { try {
size = retrieveFileSize(); mUrl = new URL(download);
} catch (Exception e) { check();
return;
} catch (MalformedURLException e) {
//fallthrough
}
}
}
Log.d(Config.LOGTAG,"unable to retrieve actual download url");
retrieveFailed(null);
});
}
private void retrieveFailed(@Nullable Exception e) {
changeStatus(STATUS_OFFER_CHECK_FILESIZE); changeStatus(STATUS_OFFER_CHECK_FILESIZE);
Log.d(Config.LOGTAG, "io exception in http file size checker: " + e.getMessage());
if (interactive) { if (interactive) {
if (e != null) {
showToastForException(e); showToastForException(e);
}
} else { } else {
HttpDownloadConnection.this.acceptedAutomatically = false; HttpDownloadConnection.this.acceptedAutomatically = false;
HttpDownloadConnection.this.mXmppConnectionService.getNotificationService().push(message); HttpDownloadConnection.this.mXmppConnectionService.getNotificationService().push(message);
} }
cancel(); cancel();
}
private void check() {
long size;
try {
size = retrieveFileSize();
} catch (Exception e) {
Log.d(Config.LOGTAG, "io exception in http file size checker: " + e.getMessage());
retrieveFailed(e);
return; return;
} }
file.setExpectedSize(size); file.setExpectedSize(size);
@ -226,10 +270,14 @@ public class HttpDownloadConnection implements Transferable {
} else { } else {
connection = (HttpURLConnection) mUrl.openConnection(); connection = (HttpURLConnection) mUrl.openConnection();
} }
if (method == Method.P1_S3) {
connection.setRequestMethod("GET");
connection.addRequestProperty("Range","bytes=0-0");
} else {
connection.setRequestMethod("HEAD"); connection.setRequestMethod("HEAD");
}
connection.setUseCaches(false); connection.setUseCaches(false);
Log.d(Config.LOGTAG, "url: " + connection.getURL().toString()); Log.d(Config.LOGTAG, "url: " + connection.getURL().toString());
Log.d(Config.LOGTAG, "connection: " + connection.toString());
connection.setRequestProperty("User-Agent", mXmppConnectionService.getIqGenerator().getIdentityName()); connection.setRequestProperty("User-Agent", mXmppConnectionService.getIqGenerator().getIdentityName());
if (connection instanceof HttpsURLConnection) { if (connection instanceof HttpsURLConnection) {
mHttpConnectionManager.setupTrustManager((HttpsURLConnection) connection, interactive); mHttpConnectionManager.setupTrustManager((HttpsURLConnection) connection, interactive);
@ -237,7 +285,18 @@ public class HttpDownloadConnection implements Transferable {
connection.setConnectTimeout(Config.SOCKET_TIMEOUT * 1000); connection.setConnectTimeout(Config.SOCKET_TIMEOUT * 1000);
connection.setReadTimeout(Config.SOCKET_TIMEOUT * 1000); connection.setReadTimeout(Config.SOCKET_TIMEOUT * 1000);
connection.connect(); connection.connect();
String contentLength = connection.getHeaderField("Content-Length"); String contentLength;
if (method == Method.P1_S3) {
String contentRange = connection.getHeaderField("Content-Range");
String[] contentRangeParts = contentRange == null ? new String[0] : contentRange.split("/");
if (contentRangeParts.length != 2) {
contentLength = null;
} else {
contentLength = contentRangeParts[1];
}
} else {
contentLength = connection.getHeaderField("Content-Length");
}
connection.disconnect(); connection.disconnect();
if (contentLength == null) { if (contentLength == null) {
throw new IOException("no content-length found in HEAD response"); throw new IOException("no content-length found in HEAD response");
@ -255,7 +314,7 @@ public class HttpDownloadConnection implements Transferable {
private class FileDownloader implements Runnable { private class FileDownloader implements Runnable {
private boolean interactive = false; private final boolean interactive;
private OutputStream os; private OutputStream os;
@ -374,7 +433,9 @@ public class HttpDownloadConnection implements Transferable {
message.setType(Message.TYPE_FILE); message.setType(Message.TYPE_FILE);
final URL url; final URL url;
final String ref = mUrl.getRef(); final String ref = mUrl.getRef();
if (ref != null && AesGcmURLStreamHandler.IV_KEY.matcher(ref).matches()) { if (method == Method.P1_S3) {
url = message.getFileParams().url;
} else if (ref != null && AesGcmURLStreamHandler.IV_KEY.matcher(ref).matches()) {
url = CryptoHelper.toAesGcmUrl(mUrl); url = CryptoHelper.toAesGcmUrl(mUrl);
} else { } else {
url = mUrl; url = mUrl;