reintroduce support for old http upload

Daniel Gultsch created

Change summary

src/main/java/eu/siacs/conversations/generator/IqGenerator.java | 10 
src/main/java/eu/siacs/conversations/http/Method.java           |  6 
src/main/java/eu/siacs/conversations/http/SlotRequester.java    | 33 ++
src/main/java/eu/siacs/conversations/xml/Namespace.java         |  1 
src/main/java/eu/siacs/conversations/xmpp/XmppConnection.java   | 48 +-
5 files changed, 74 insertions(+), 24 deletions(-)

Detailed changes

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

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;

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

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

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<Entry<Jid, ServiceDiscoveryResult>> 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<Entry<Jid, ServiceDiscoveryResult>> 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<Entry<Jid, ServiceDiscoveryResult>> 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<Entry<Jid, ServiceDiscoveryResult>> 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() {