diff --git a/src/main/java/eu/siacs/conversations/generator/IqGenerator.java b/src/main/java/eu/siacs/conversations/generator/IqGenerator.java index e2b7b5afb..c1a1946c9 100644 --- a/src/main/java/eu/siacs/conversations/generator/IqGenerator.java +++ b/src/main/java/eu/siacs/conversations/generator/IqGenerator.java @@ -351,6 +351,16 @@ public class IqGenerator extends AbstractGenerator { return packet; } + public IqPacket requestHttpUploadLegacySlot(Jid host, DownloadableFile file, String mime) { + IqPacket packet = new IqPacket(IqPacket.TYPE.GET); + packet.setTo(host); + Element request = packet.addChild("request", Namespace.HTTP_UPLOAD_LEGACY); + request.addChild("filename").setContent(convertFilename(file.getName())); + request.addChild("size").setContent(String.valueOf(file.getExpectedSize())); + request.addChild("content-type").setContent(mime); + return packet; + } + public IqPacket requestP1S3Slot(Jid host, String md5) { IqPacket packet = new IqPacket(IqPacket.TYPE.SET); packet.setTo(host); diff --git a/src/main/java/eu/siacs/conversations/http/Method.java b/src/main/java/eu/siacs/conversations/http/Method.java index d4bcc2e25..2f731995b 100644 --- a/src/main/java/eu/siacs/conversations/http/Method.java +++ b/src/main/java/eu/siacs/conversations/http/Method.java @@ -33,14 +33,16 @@ import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.xmpp.XmppConnection; public enum Method { - P1_S3, HTTP_UPLOAD; + P1_S3, HTTP_UPLOAD, HTTP_UPLOAD_LEGACY; public static Method determine(Account account) { XmppConnection.Features features = account.getXmppConnection() == null ? null : account.getXmppConnection().getFeatures(); if (features == null) { return HTTP_UPLOAD; } - if (features.httpUpload(0)) { + if (features.useLegacyHttpUpload()) { + return HTTP_UPLOAD_LEGACY; + } else if (features.httpUpload(0)) { return HTTP_UPLOAD; } else if (features.p1S3FileTransfer()) { return P1_S3; diff --git a/src/main/java/eu/siacs/conversations/http/SlotRequester.java b/src/main/java/eu/siacs/conversations/http/SlotRequester.java index 35bb111bf..c0717c72e 100644 --- a/src/main/java/eu/siacs/conversations/http/SlotRequester.java +++ b/src/main/java/eu/siacs/conversations/http/SlotRequester.java @@ -58,11 +58,42 @@ public class SlotRequester { if (method == Method.HTTP_UPLOAD) { Jid host = account.getXmppConnection().findDiscoItemByFeature(Namespace.HTTP_UPLOAD); requestHttpUpload(account, host, file, mime, callback); + } else if (method == Method.HTTP_UPLOAD_LEGACY) { + Jid host = account.getXmppConnection().findDiscoItemByFeature(Namespace.HTTP_UPLOAD_LEGACY); + requestHttpUploadLegacy(account, host, file, mime, callback); } else { requestP1S3(account, Jid.of(account.getServer()), file.getName(), md5, callback); } } + private void requestHttpUploadLegacy(Account account, Jid host, DownloadableFile file, String mime, OnSlotRequested callback) { + IqPacket request = service.getIqGenerator().requestHttpUploadLegacySlot(host, file, mime); + service.sendIqPacket(account, request, (a, packet) -> { + if (packet.getType() == IqPacket.TYPE.RESULT) { + Element slotElement = packet.findChild("slot", Namespace.HTTP_UPLOAD_LEGACY); + if (slotElement != null) { + try { + final String putUrl = slotElement.findChildContent("put"); + final String getUrl = slotElement.findChildContent("get"); + if (getUrl != null && putUrl != null) { + Slot slot = new Slot(new URL(putUrl)); + slot.getUrl = new URL(getUrl); + slot.headers = new HashMap<>(); + slot.headers.put("Content-Type", mime == null ? "application/octet-stream" : mime); + callback.success(slot); + return; + } + } catch (MalformedURLException e) { + //fall through + } + } + } + Log.d(Config.LOGTAG, account.getJid().toString() + ": invalid response to slot request " + packet); + callback.failure(IqParser.extractErrorMessage(packet)); + }); + + } + private void requestHttpUpload(Account account, Jid host, DownloadableFile file, String mime, OnSlotRequested callback) { IqPacket request = service.getIqGenerator().requestHttpUploadSlot(host, file, mime); service.sendIqPacket(account, request, (a, packet) -> { @@ -85,9 +116,9 @@ public class SlotRequester { if (HttpUploadConnection.WHITE_LISTED_HEADERS.contains(name) && value != null && !value.trim().contains("\n")) { slot.headers.put(name, value.trim()); } - slot.headers.put("Content-Type", mime == null ? "application/octet-stream" : mime); } } + slot.headers.put("Content-Type", mime == null ? "application/octet-stream" : mime); callback.success(slot); return; } diff --git a/src/main/java/eu/siacs/conversations/xml/Namespace.java b/src/main/java/eu/siacs/conversations/xml/Namespace.java index 6eb79cb28..3d96a28c8 100644 --- a/src/main/java/eu/siacs/conversations/xml/Namespace.java +++ b/src/main/java/eu/siacs/conversations/xml/Namespace.java @@ -6,6 +6,7 @@ public final class Namespace { public static final String REGISTER = "jabber:iq:register"; public static final String BYTE_STREAMS = "http://jabber.org/protocol/bytestreams"; public static final String HTTP_UPLOAD = "urn:xmpp:http:upload:0"; + public static final String HTTP_UPLOAD_LEGACY = "urn:xmpp:http:upload"; public static final String STANZA_IDS = "urn:xmpp:sid:0"; public static final String MAM = "urn:xmpp:mam:2"; public static final String MAM_LEGACY = "urn:xmpp:mam:0"; diff --git a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java index 80201bc68..1376edea0 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java +++ b/src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java @@ -1815,36 +1815,42 @@ public class XmppConnection implements Runnable { if (Config.DISABLE_HTTP_UPLOAD) { return false; } else { - List> items = findDiscoItemsByFeature(Namespace.HTTP_UPLOAD); - if (items.size() > 0) { - try { - long maxsize = Long.parseLong(items.get(0).getValue().getExtendedDiscoInformation(Namespace.HTTP_UPLOAD, "max-file-size")); - if (filesize <= maxsize) { - return true; - } else { - Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": http upload is not available for files with size " + filesize + " (max is " + maxsize + ")"); - return false; + for(String namespace : new String[]{Namespace.HTTP_UPLOAD, Namespace.HTTP_UPLOAD_LEGACY}) { + List> items = findDiscoItemsByFeature(namespace); + if (items.size() > 0) { + try { + long maxsize = Long.parseLong(items.get(0).getValue().getExtendedDiscoInformation(namespace, "max-file-size")); + if (filesize <= maxsize) { + return true; + } else { + Log.d(Config.LOGTAG, account.getJid().asBareJid() + ": http upload is not available for files with size " + filesize + " (max is " + maxsize + ")"); + return false; + } + } catch (Exception e) { + //ignored } - } catch (Exception e) { - return true; } - } else { - return false; } + return false; } } + public boolean useLegacyHttpUpload() { + return findDiscoItemByFeature(Namespace.HTTP_UPLOAD) == null && findDiscoItemByFeature(Namespace.HTTP_UPLOAD_LEGACY) != null; + } + public long getMaxHttpUploadSize() { - List> items = findDiscoItemsByFeature(Namespace.HTTP_UPLOAD); - if (items.size() > 0) { - try { - return Long.parseLong(items.get(0).getValue().getExtendedDiscoInformation(Namespace.HTTP_UPLOAD, "max-file-size")); - } catch (Exception e) { - return -1; + for(String namespace : new String[]{Namespace.HTTP_UPLOAD, Namespace.HTTP_UPLOAD_LEGACY}) { + List> items = findDiscoItemsByFeature(namespace); + if (items.size() > 0) { + try { + return Long.parseLong(items.get(0).getValue().getExtendedDiscoInformation(namespace, "max-file-size")); + } catch (Exception e) { + //ignored + } } - } else { - return -1; } + return -1; } public boolean stanzaIds() {