make sure that http upload/download is not startetd multiple times

Daniel Gultsch created

Change summary

src/main/java/eu/siacs/conversations/http/HttpConnectionManager.java  | 142 
src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java |  16 
src/main/java/eu/siacs/conversations/http/HttpUploadConnection.java   |  20 
3 files changed, 102 insertions(+), 76 deletions(-)

Detailed changes

src/main/java/eu/siacs/conversations/http/HttpConnectionManager.java 🔗

@@ -11,8 +11,8 @@ import java.net.Proxy;
 import java.net.URL;
 import java.security.KeyManagementException;
 import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
 import java.util.List;
-import java.util.concurrent.CopyOnWriteArrayList;
 
 import javax.net.ssl.HostnameVerifier;
 import javax.net.ssl.HttpsURLConnection;
@@ -25,68 +25,86 @@ import eu.siacs.conversations.entities.Message;
 import eu.siacs.conversations.services.AbstractConnectionManager;
 import eu.siacs.conversations.services.XmppConnectionService;
 import eu.siacs.conversations.utils.TLSSocketFactory;
-import eu.siacs.conversations.xmpp.OnAdvancedStreamFeaturesLoaded;
 
 public class HttpConnectionManager extends AbstractConnectionManager {
 
-	public HttpConnectionManager(XmppConnectionService service) {
-		super(service);
-	}
-
-	private List<HttpDownloadConnection> downloadConnections = new CopyOnWriteArrayList<>();
-	private List<HttpUploadConnection> uploadConnections = new CopyOnWriteArrayList<>();
-
-	public HttpDownloadConnection createNewDownloadConnection(Message message) {
-		return this.createNewDownloadConnection(message, false);
-	}
-
-	public HttpDownloadConnection createNewDownloadConnection(Message message, boolean interactive) {
-		HttpDownloadConnection connection = new HttpDownloadConnection(this);
-		connection.init(message,interactive);
-		this.downloadConnections.add(connection);
-		return connection;
-	}
-
-	public void createNewUploadConnection(Message message, boolean delay) {
-		HttpUploadConnection connection = new HttpUploadConnection(Method.determine(message.getConversation().getAccount()), this);
-		connection.init(message,delay);
-		this.uploadConnections.add(connection);
-	}
-
-	public boolean checkConnection(Message message) {
-		final Account account = message.getConversation().getAccount();
-		final URL url = message.getFileParams().url;
-		if (url.getProtocol().equalsIgnoreCase(P1S3UrlStreamHandler.PROTOCOL_NAME) && account.getStatus() != Account.State.ONLINE) {
-			return false;
-		}
-		return mXmppConnectionService.hasInternetConnection();
-	}
-
-	public void finishConnection(HttpDownloadConnection connection) {
-		this.downloadConnections.remove(connection);
-	}
-
-	public void finishUploadConnection(HttpUploadConnection httpUploadConnection) {
-		this.uploadConnections.remove(httpUploadConnection);
-	}
-
-	public void setupTrustManager(final HttpsURLConnection connection, final boolean interactive) {
-		final X509TrustManager trustManager;
-		final HostnameVerifier hostnameVerifier = mXmppConnectionService.getMemorizingTrustManager().wrapHostnameVerifier(new StrictHostnameVerifier(), interactive);
-		if (interactive) {
-			trustManager = mXmppConnectionService.getMemorizingTrustManager().getInteractive();
-		} else {
-			trustManager = mXmppConnectionService.getMemorizingTrustManager().getNonInteractive();
-		}
-		try {
-			final SSLSocketFactory sf = new TLSSocketFactory(new X509TrustManager[]{trustManager}, mXmppConnectionService.getRNG());
-			connection.setSSLSocketFactory(sf);
-			connection.setHostnameVerifier(hostnameVerifier);
-		} catch (final KeyManagementException | NoSuchAlgorithmException ignored) {
-		}
-	}
-
-	public static Proxy getProxy() throws IOException {
-		return new Proxy(Proxy.Type.HTTP, new InetSocketAddress(InetAddress.getByAddress(new byte[]{127,0,0,1}), 8118));
-	}
+    private final List<HttpDownloadConnection> downloadConnections = new ArrayList<>();
+    private final List<HttpUploadConnection> uploadConnections = new ArrayList<>();
+
+    public HttpConnectionManager(XmppConnectionService service) {
+        super(service);
+    }
+
+    public static Proxy getProxy() throws IOException {
+        return new Proxy(Proxy.Type.HTTP, new InetSocketAddress(InetAddress.getByAddress(new byte[]{127, 0, 0, 1}), 8118));
+    }
+
+    public void createNewDownloadConnection(Message message) {
+        this.createNewDownloadConnection(message, false);
+    }
+
+    public void createNewDownloadConnection(final Message message, boolean interactive) {
+        synchronized (this.downloadConnections) {
+            for(HttpDownloadConnection connection : this.downloadConnections) {
+                if (connection.getMessage() == message) {
+                    Log.d(Config.LOGTAG, message.getConversation().getAccount().getJid().asBareJid() + ": download already in progress");
+                    return;
+                }
+            }
+            final HttpDownloadConnection connection = new HttpDownloadConnection(message, this);
+            connection.init(interactive);
+            this.downloadConnections.add(connection);
+        }
+    }
+
+    public void createNewUploadConnection(final Message message, boolean delay) {
+        synchronized (this.uploadConnections) {
+            for (HttpUploadConnection connection : this.uploadConnections) {
+                if (connection.getMessage() == message) {
+                    Log.d(Config.LOGTAG, message.getConversation().getAccount().getJid().asBareJid() + ": upload already in progress");
+                    return;
+                }
+            }
+            HttpUploadConnection connection = new HttpUploadConnection(message, Method.determine(message.getConversation().getAccount()), this);
+            connection.init(delay);
+            this.uploadConnections.add(connection);
+        }
+    }
+
+    public boolean checkConnection(Message message) {
+        final Account account = message.getConversation().getAccount();
+        final URL url = message.getFileParams().url;
+        if (url.getProtocol().equalsIgnoreCase(P1S3UrlStreamHandler.PROTOCOL_NAME) && account.getStatus() != Account.State.ONLINE) {
+            return false;
+        }
+        return mXmppConnectionService.hasInternetConnection();
+    }
+
+    void finishConnection(HttpDownloadConnection connection) {
+        synchronized (this.downloadConnections) {
+            this.downloadConnections.remove(connection);
+        }
+    }
+
+    void finishUploadConnection(HttpUploadConnection httpUploadConnection) {
+        synchronized (this.uploadConnections) {
+            this.uploadConnections.remove(httpUploadConnection);
+        }
+    }
+
+    void setupTrustManager(final HttpsURLConnection connection, final boolean interactive) {
+        final X509TrustManager trustManager;
+        final HostnameVerifier hostnameVerifier = mXmppConnectionService.getMemorizingTrustManager().wrapHostnameVerifier(new StrictHostnameVerifier(), interactive);
+        if (interactive) {
+            trustManager = mXmppConnectionService.getMemorizingTrustManager().getInteractive();
+        } else {
+            trustManager = mXmppConnectionService.getMemorizingTrustManager().getNonInteractive();
+        }
+        try {
+            final SSLSocketFactory sf = new TLSSocketFactory(new X509TrustManager[]{trustManager}, mXmppConnectionService.getRNG());
+            connection.setSSLSocketFactory(sf);
+            connection.setHostnameVerifier(hostnameVerifier);
+        } catch (final KeyManagementException | NoSuchAlgorithmException ignored) {
+        }
+    }
 }

src/main/java/eu/siacs/conversations/http/HttpDownloadConnection.java 🔗

@@ -39,7 +39,7 @@ public class HttpDownloadConnection implements Transferable {
 	private XmppConnectionService mXmppConnectionService;
 
 	private URL mUrl;
-	private Message message;
+	private final Message message;
 	private DownloadableFile file;
 	private int mStatus = Transferable.STATUS_UNKNOWN;
 	private boolean acceptedAutomatically = false;
@@ -48,7 +48,8 @@ public class HttpDownloadConnection implements Transferable {
 	private boolean canceled = false;
 	private Method method = Method.HTTP_UPLOAD;
 
-	HttpDownloadConnection(HttpConnectionManager manager) {
+	HttpDownloadConnection(Message message, HttpConnectionManager manager) {
+		this.message = message;
 		this.mHttpConnectionManager = manager;
 		this.mXmppConnectionService = manager.getXmppConnectionService();
 		this.mUseTor = mXmppConnectionService.useTorToConnect();
@@ -68,12 +69,7 @@ public class HttpDownloadConnection implements Transferable {
 		}
 	}
 
-	public void init(Message message) {
-		init(message, false);
-	}
-
-	public void init(Message message, boolean interactive) {
-		this.message = message;
+	public void init(boolean interactive) {
 		this.message.setTransferable(this);
 		try {
 			if (message.hasFileOnRemoteHost()) {
@@ -195,6 +191,10 @@ public class HttpDownloadConnection implements Transferable {
 		return this.mProgress;
 	}
 
+	public Message getMessage() {
+		return message;
+	}
+
 	private class FileSizeChecker implements Runnable {
 
 		private final boolean interactive;

src/main/java/eu/siacs/conversations/http/HttpUploadConnection.java 🔗

@@ -43,14 +43,15 @@ public class HttpUploadConnection implements Transferable {
 	private boolean cancelled = false;
 	private boolean delayed = false;
 	private DownloadableFile file;
-	private Message message;
+	private final Message message;
 	private String mime;
 	private SlotRequester.Slot slot;
 	private byte[] key = null;
 
 	private long transmitted = 0;
 
-	public HttpUploadConnection(Method method, HttpConnectionManager httpConnectionManager) {
+	public HttpUploadConnection(Message message, Method method, HttpConnectionManager httpConnectionManager) {
+		this.message = message;
 		this.method = method;
 		this.mHttpConnectionManager = httpConnectionManager;
 		this.mXmppConnectionService = httpConnectionManager.getXmppConnectionService();
@@ -87,13 +88,16 @@ public class HttpUploadConnection implements Transferable {
 	}
 
 	private void fail(String errorMessage) {
+		finish();
+		mXmppConnectionService.markMessage(message, Message.STATUS_SEND_FAILED, cancelled ? Message.ERROR_MESSAGE_CANCELLED : errorMessage);
+	}
+
+	private void finish() {
 		mHttpConnectionManager.finishUploadConnection(this);
 		message.setTransferable(null);
-		mXmppConnectionService.markMessage(message, Message.STATUS_SEND_FAILED, cancelled ? Message.ERROR_MESSAGE_CANCELLED : errorMessage);
 	}
 
-	public void init(Message message, boolean delay) {
-		this.message = message;
+	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) {
@@ -211,7 +215,7 @@ public class HttpUploadConnection implements Transferable {
 				}
 				mXmppConnectionService.getFileBackend().updateFileParams(message, get);
 				mXmppConnectionService.getFileBackend().updateMediaScanner(file);
-				message.setTransferable(null);
+				finish();
 				message.setCounterpart(message.getConversation().getJid().asBareJid());
 				mXmppConnectionService.resendMessage(message, delayed);
 			} else {
@@ -231,4 +235,8 @@ public class HttpUploadConnection implements Transferable {
 			WakeLockHelper.release(wakeLock);
 		}
 	}
+
+	public Message getMessage() {
+		return message;
+	}
 }