diff options
Diffstat (limited to 'src/main/java/de/thedevstack/conversationsplus/http')
3 files changed, 4 insertions, 468 deletions
diff --git a/src/main/java/de/thedevstack/conversationsplus/http/HttpClient.java b/src/main/java/de/thedevstack/conversationsplus/http/HttpClient.java index 7e12a890..e1a38067 100644 --- a/src/main/java/de/thedevstack/conversationsplus/http/HttpClient.java +++ b/src/main/java/de/thedevstack/conversationsplus/http/HttpClient.java @@ -6,14 +6,15 @@ import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.X509TrustManager; import de.thedevstack.conversationsplus.ConversationsPlusApplication; -import de.thedevstack.conversationsplus.utils.CryptoHelper; -import de.thedevstack.conversationsplus.utils.SSLSocketHelper; + +import eu.siacs.conversations.utils.CryptoHelper; +import eu.siacs.conversations.utils.SSLSocketHelper; + import okhttp3.OkHttpClient; /** diff --git a/src/main/java/de/thedevstack/conversationsplus/http/HttpConnectionManager.java b/src/main/java/de/thedevstack/conversationsplus/http/HttpConnectionManager.java deleted file mode 100644 index 011e2529..00000000 --- a/src/main/java/de/thedevstack/conversationsplus/http/HttpConnectionManager.java +++ /dev/null @@ -1,90 +0,0 @@ -package de.thedevstack.conversationsplus.http; - -import org.apache.http.conn.ssl.StrictHostnameVerifier; - -import java.io.IOException; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.Proxy; -import java.security.KeyManagementException; -import java.security.NoSuchAlgorithmException; -import java.util.List; -import java.util.concurrent.CopyOnWriteArrayList; - -import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.HttpsURLConnection; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLSocketFactory; -import javax.net.ssl.X509TrustManager; - -import de.thedevstack.conversationsplus.ConversationsPlusApplication; -import de.thedevstack.conversationsplus.entities.Message; -import de.thedevstack.conversationsplus.services.AbstractConnectionManager; -import de.thedevstack.conversationsplus.utils.CryptoHelper; -import de.thedevstack.conversationsplus.utils.MessageUtil; -import de.thedevstack.conversationsplus.utils.SSLSocketHelper; - -public class HttpConnectionManager extends AbstractConnectionManager { - private static HttpConnectionManager INSTANCE; - - public static void init() { - INSTANCE = new HttpConnectionManager(); - } - - private List<HttpDownloadConnection> downloadConnections = new CopyOnWriteArrayList<>(); - - public static HttpDownloadConnection createNewDownloadConnection(Message message) { - return createNewDownloadConnection(message, false); - } - - public static HttpDownloadConnection createNewDownloadConnection(Message message, boolean interactive) { - if (MessageUtil.needsDownload(message)) { - HttpDownloadConnection connection = new HttpDownloadConnection(INSTANCE); - connection.init(message, interactive); - INSTANCE.downloadConnections.add(connection); - return connection; - } - return null; - } - - public void finishConnection(HttpDownloadConnection connection) { - this.downloadConnections.remove(connection); - } - - public static void setupTrustManager(final HttpsURLConnection connection, final boolean interactive) { - final X509TrustManager trustManager; - final HostnameVerifier hostnameVerifier; - if (interactive) { - trustManager = ConversationsPlusApplication.getMemorizingTrustManager(); - hostnameVerifier = ConversationsPlusApplication.getMemorizingTrustManager().wrapHostnameVerifier( - new StrictHostnameVerifier()); - } else { - trustManager = ConversationsPlusApplication.getMemorizingTrustManager() - .getNonInteractive(); - hostnameVerifier = ConversationsPlusApplication.getMemorizingTrustManager() - .wrapHostnameVerifierNonInteractive( - new StrictHostnameVerifier()); - } - try { - final SSLContext sc = SSLSocketHelper.getSSLContext(); - sc.init(null, new X509TrustManager[]{trustManager}, - ConversationsPlusApplication.getSecureRandom()); - - final SSLSocketFactory sf = sc.getSocketFactory(); - final String[] cipherSuites = CryptoHelper.getOrderedCipherSuites( - sf.getSupportedCipherSuites()); - if (cipherSuites.length > 0) { - sc.getDefaultSSLParameters().setCipherSuites(cipherSuites); - - } - - connection.setSSLSocketFactory(sf); - connection.setHostnameVerifier(hostnameVerifier); - } catch (final KeyManagementException | NoSuchAlgorithmException ignored) { - } - } - - public Proxy getProxy() throws IOException { - return new Proxy(Proxy.Type.HTTP, new InetSocketAddress(InetAddress.getLocalHost(), 8118)); - } -} diff --git a/src/main/java/de/thedevstack/conversationsplus/http/HttpDownloadConnection.java b/src/main/java/de/thedevstack/conversationsplus/http/HttpDownloadConnection.java deleted file mode 100644 index 07f308fe..00000000 --- a/src/main/java/de/thedevstack/conversationsplus/http/HttpDownloadConnection.java +++ /dev/null @@ -1,375 +0,0 @@ -package de.thedevstack.conversationsplus.http; - -import android.os.PowerManager; -import android.util.Log; - -import java.io.BufferedInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.HttpURLConnection; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.concurrent.CancellationException; - -import javax.net.ssl.HttpsURLConnection; -import javax.net.ssl.SSLHandshakeException; - -import de.thedevstack.android.logcat.Logging; -import de.thedevstack.conversationsplus.ConversationsPlusApplication; -import de.thedevstack.conversationsplus.ConversationsPlusPreferences; -import de.thedevstack.conversationsplus.entities.FileParams; -import de.thedevstack.conversationsplus.enums.FileStatus; -import de.thedevstack.conversationsplus.exceptions.RemoteFileNotFoundException; -import de.thedevstack.conversationsplus.utils.MessageUtil; -import de.thedevstack.conversationsplus.utils.StreamUtil; -import de.thedevstack.conversationsplus.Config; -import de.thedevstack.conversationsplus.R; -import de.thedevstack.conversationsplus.entities.DownloadableFile; -import de.thedevstack.conversationsplus.entities.Message; -import de.thedevstack.conversationsplus.entities.Transferable; -import de.thedevstack.conversationsplus.entities.TransferablePlaceholder; -import de.thedevstack.conversationsplus.persistance.FileBackend; -import de.thedevstack.conversationsplus.services.AbstractConnectionManager; -import de.thedevstack.conversationsplus.services.XmppConnectionService; -import de.thedevstack.conversationsplus.utils.CryptoHelper; -import de.thedevstack.conversationsplus.utils.FileUtils; -import de.thedevstack.conversationsplus.utils.XmppConnectionServiceAccessor; - -public class HttpDownloadConnection implements Transferable { - - private HttpConnectionManager mHttpConnectionManager; - private XmppConnectionService mXmppConnectionService; - - private URL mUrl; - private Message message; - private DownloadableFile file; - private int mStatus = Transferable.STATUS_UNKNOWN; - private boolean acceptedAutomatically = false; - private int mProgress = 0; - private boolean canceled = false; - - public HttpDownloadConnection(HttpConnectionManager manager) { - this.mHttpConnectionManager = manager; - this.mXmppConnectionService = XmppConnectionServiceAccessor.xmppConnectionService; - } - - @Override - public boolean start() { - if (mXmppConnectionService.hasInternetConnection()) { - if (this.mStatus == STATUS_OFFER_CHECK_FILESIZE) { - checkFileSize(true); - } else { - new Thread(new FileDownloader(true)).start(); - } - return true; - } else { - return false; - } - } - - public void init(Message message) { - init(message, false); - } - - public void init(Message message, boolean interactive) { - this.message = message; - this.message.setTransferable(this); - try { - String url = (null != message && null != message.getFileParams()) ? message.getFileParams().getUrl() : null; - if (null == url) { - /* - * If this code is reached and the URL is null something went wrong. - * Try again to extract the file parameters from the message. - */ - MessageUtil.extractFileParamsFromBody(message); - url = (null != message.getFileParams()) ? message.getFileParams().getUrl() : null; - if (null == url) { - message.setTreatAsDownloadable(Message.Decision.NEVER); // TODO find sth better - this.cancel(); - return; - } - } - mUrl = new URL(url); - final String sUrlFilename = mUrl.getPath().substring(mUrl.getPath().lastIndexOf('/') + 1).toLowerCase(); - final String lastPart = FileUtils.getLastExtension(sUrlFilename); - - if (!lastPart.isEmpty() && ("pgp".equals(lastPart) || "gpg".equals(lastPart))) { - this.message.setEncryption(Message.ENCRYPTION_PGP); - } else if (message.getEncryption() != Message.ENCRYPTION_OTR - && message.getEncryption() != Message.ENCRYPTION_AXOLOTL) { - this.message.setEncryption(Message.ENCRYPTION_NONE); - } - - String extension; - String originalFilename; - if (!lastPart.isEmpty() && VALID_CRYPTO_EXTENSIONS.contains(lastPart)) { - extension = FileUtils.getSecondToLastExtension(sUrlFilename); - originalFilename = sUrlFilename.replace("." + lastPart, ""); - } else { - extension = lastPart; - originalFilename = sUrlFilename; - } - message.setRelativeFilePath(message.getUuid() + "." + extension); - this.file = FileBackend.getFile(message, false); - - FileParams fileParams = message.getFileParams(); - if (null == fileParams) { - fileParams = new FileParams(); - message.setFileParams(fileParams); - } - fileParams.setOriginalFilename(originalFilename); - - if ((this.message.getEncryption() == Message.ENCRYPTION_OTR - || this.message.getEncryption() == Message.ENCRYPTION_AXOLOTL) - && this.file.getKey() == null) { - this.message.setEncryption(Message.ENCRYPTION_NONE); - } - checkFileSize(interactive); - } catch (MalformedURLException e) { - this.cancel(); - } - } - - private void checkFileSize(boolean interactive) { - new Thread(new FileSizeChecker(interactive)).start(); - } - - @Override - public void cancel() { - this.canceled = true; - mHttpConnectionManager.finishConnection(this); - if (message.isFileOrImage()) { - message.setTransferable(new TransferablePlaceholder(Transferable.STATUS_DELETED)); - } else { - message.setTransferable(null); - } - mXmppConnectionService.updateConversationUi(); - } - - private void finish() { - FileBackend.updateMediaScanner(file, mXmppConnectionService); - message.setTransferable(null); - MessageUtil.setAndSaveFileStatus(this.message, FileStatus.DOWNLOADED); - mHttpConnectionManager.finishConnection(this); - if (message.getEncryption() == Message.ENCRYPTION_PGP) { - message.getConversation().getAccount().getPgpDecryptionService().add(message); - } - mXmppConnectionService.updateConversationUi(); - if (acceptedAutomatically) { - mXmppConnectionService.getNotificationService().push(message); - } - } - - private void changeStatus(int status) { - this.mStatus = status; - mXmppConnectionService.updateConversationUi(); - } - - private void showToastForException(Exception e) { - e.printStackTrace(); - if (e instanceof java.net.UnknownHostException) { - mXmppConnectionService.showErrorToastInUi(R.string.download_failed_server_not_found); - } else if (e instanceof java.net.ConnectException) { - mXmppConnectionService.showErrorToastInUi(R.string.download_failed_could_not_connect); - } else if (!(e instanceof CancellationException)) { - mXmppConnectionService.showErrorToastInUi(R.string.download_failed_file_not_found); - } - } - - private class FileSizeChecker implements Runnable { - - private boolean interactive = false; - - public FileSizeChecker(boolean interactive) { - this.interactive = interactive; - } - - @Override - public void run() { - long size; - try { - size = retrieveFileSize(); - } catch (SSLHandshakeException e) { - changeStatus(STATUS_OFFER_CHECK_FILESIZE); - HttpDownloadConnection.this.acceptedAutomatically = false; - HttpDownloadConnection.this.mXmppConnectionService.getNotificationService().push(message); - return; - } catch (RemoteFileNotFoundException e) { - message.setNoDownloadable(); // TODO Set remote file status to not-available - cancel(); - return; - } catch (IOException e) { - Log.d(Config.LOGTAG, "io exception in http file size checker: " + e.getMessage()); - if (interactive) { - showToastForException(e); - } - cancel(); - return; - } - file.setExpectedSize(size); - if (mHttpConnectionManager.hasStoragePermission() - && size != -1 - && size <= ConversationsPlusPreferences.autoAcceptFileSize() - && mXmppConnectionService.isDownloadAllowedInConnection()) { - HttpDownloadConnection.this.acceptedAutomatically = true; - new Thread(new FileDownloader(interactive)).start(); - } else { - changeStatus(STATUS_OFFER); - HttpDownloadConnection.this.acceptedAutomatically = false; - HttpDownloadConnection.this.mXmppConnectionService.getNotificationService().push(message); - } - } - - private long retrieveFileSize() throws IOException { - try { - Logging.d(Config.LOGTAG, "retrieve file size. interactive:" + String.valueOf(interactive)); - changeStatus(STATUS_CHECKING); - HttpURLConnection connection = (HttpURLConnection) mUrl.openConnection(); - connection.setRequestMethod("HEAD"); - Logging.d(Config.LOGTAG, "url: " + connection.getURL().toString()); - Logging.d(Config.LOGTAG, "connection: " + connection.toString()); - connection.setRequestProperty("User-Agent", ConversationsPlusApplication.getNameAndVersion()); - // https://code.google.com/p/android/issues/detail?id=24672 - connection.setRequestProperty("Accept-Encoding", ""); - if (connection instanceof HttpsURLConnection) { - mHttpConnectionManager.setupTrustManager((HttpsURLConnection) connection, interactive); - } - connection.connect(); - if (connection.getResponseCode() == HttpURLConnection.HTTP_NOT_FOUND) { - Logging.d(Config.LOGTAG, "remote file not found"); - throw new RemoteFileNotFoundException(); - } - String contentLength = connection.getHeaderField("Content-Length"); - connection.disconnect(); - if (contentLength == null) { - return -1; - } - return Long.parseLong(contentLength, 10); - } catch (RemoteFileNotFoundException e) { - throw e; - } catch (IOException e) { - return -1; - } catch (NumberFormatException e) { - return -1; - } - } - - } - - private class FileDownloader implements Runnable { - - private boolean interactive = false; - - private OutputStream os; - - public FileDownloader(boolean interactive) { - this.interactive = interactive; - } - - @Override - public void run() { - try { - changeStatus(STATUS_DOWNLOADING); - download(); - updateImageBounds(); - finish(); - } catch (SSLHandshakeException e) { - changeStatus(STATUS_OFFER); - } catch (Exception e) { - if (interactive) { - showToastForException(e); - } - cancel(); - } - } - - private void download() throws SSLHandshakeException, IOException { - InputStream is = null; - PowerManager.WakeLock wakeLock = ConversationsPlusApplication.createPartialWakeLock("http_download_"+message.getUuid()); - try { - wakeLock.acquire(); - HttpURLConnection connection = (HttpURLConnection) mUrl.openConnection(); - if (connection instanceof HttpsURLConnection) { - mHttpConnectionManager.setupTrustManager((HttpsURLConnection) connection, interactive); - } - connection.setRequestProperty("User-Agent", ConversationsPlusApplication.getNameAndVersion()); - final boolean tryResume = file.exists() && file.getKey() == null; - if (tryResume) { - Logging.d(Config.LOGTAG, "http download trying resume"); - long size = file.getSize(); - connection.setRequestProperty("Range", "bytes="+size+"-"); - } - connection.connect(); - is = new BufferedInputStream(connection.getInputStream()); - boolean serverResumed = "bytes".equals(connection.getHeaderField("Accept-Ranges")); - long transmitted = 0; - long expected = file.getExpectedSize(); - if (tryResume && serverResumed) { - Logging.d(Config.LOGTAG, "server resumed"); - transmitted = file.getSize(); - updateProgress((int) ((((double) transmitted) / expected) * 100)); - os = AbstractConnectionManager.createAppendedOutputStream(file); - } else { - file.getParentFile().mkdirs(); - file.createNewFile(); - os = AbstractConnectionManager.createOutputStream(file, true); - } - int count = -1; - byte[] buffer = new byte[1024]; - while ((count = is.read(buffer)) != -1) { - transmitted += count; - os.write(buffer, 0, count); - updateProgress((int) ((((double) transmitted) / expected) * 100)); - if (canceled) { - throw new CancellationException(); - } - } - } catch (CancellationException | IOException e) { - throw e; - } finally { - if (os != null) { - try { - os.flush(); - } catch (final IOException ignored) { - - } - } - StreamUtil.close(os); - StreamUtil.close(is); - wakeLock.release(); - } - } - - private void updateImageBounds() { - message.setType(Message.TYPE_FILE); - MessageUtil.updateFileParams(message, mUrl); - mXmppConnectionService.updateMessage(message); - } - - } - - public void updateProgress(int i) { - this.mProgress = i; - mXmppConnectionService.updateConversationUi(); - } - - @Override - public int getStatus() { - return this.mStatus; - } - - @Override - public long getFileSize() { - if (this.file != null) { - return this.file.getExpectedSize(); - } else { - return 0; - } - } - - @Override - public int getProgress() { - return this.mProgress; - } -} |