HttpUploadConnection.java

  1package eu.siacs.conversations.http;
  2
  3import android.util.Log;
  4
  5import java.io.IOException;
  6import java.io.InputStream;
  7import java.io.OutputStream;
  8import java.net.HttpURLConnection;
  9import java.net.MalformedURLException;
 10import java.net.URL;
 11
 12import eu.siacs.conversations.Config;
 13import eu.siacs.conversations.entities.Account;
 14import eu.siacs.conversations.entities.Downloadable;
 15import eu.siacs.conversations.entities.DownloadableFile;
 16import eu.siacs.conversations.entities.Message;
 17import eu.siacs.conversations.persistance.FileBackend;
 18import eu.siacs.conversations.services.XmppConnectionService;
 19import eu.siacs.conversations.utils.CryptoHelper;
 20import eu.siacs.conversations.utils.Xmlns;
 21import eu.siacs.conversations.xml.Element;
 22import eu.siacs.conversations.xmpp.OnIqPacketReceived;
 23import eu.siacs.conversations.xmpp.jid.Jid;
 24import eu.siacs.conversations.xmpp.stanzas.IqPacket;
 25
 26public class HttpUploadConnection implements Downloadable {
 27
 28	private HttpConnectionManager mHttpConnectionManager;
 29	private XmppConnectionService mXmppConnectionService;
 30
 31	private boolean canceled = false;
 32	private Account account;
 33	private DownloadableFile file;
 34	private Message message;
 35	private URL mGetUrl;
 36	private URL mPutUrl;
 37
 38	private byte[] key = null;
 39
 40	private long transmitted = 0;
 41	private long expected = 1;
 42
 43	public HttpUploadConnection(HttpConnectionManager httpConnectionManager) {
 44		this.mHttpConnectionManager = httpConnectionManager;
 45		this.mXmppConnectionService = httpConnectionManager.getXmppConnectionService();
 46	}
 47
 48	@Override
 49	public boolean start() {
 50		return false;
 51	}
 52
 53	@Override
 54	public int getStatus() {
 55		return STATUS_UPLOADING;
 56	}
 57
 58	@Override
 59	public long getFileSize() {
 60		return this.file.getExpectedSize();
 61	}
 62
 63	@Override
 64	public int getProgress() {
 65		return (int) ((((double) transmitted) / expected) * 100);
 66	}
 67
 68	@Override
 69	public void cancel() {
 70		this.canceled = true;
 71	}
 72
 73	private void fail() {
 74		mHttpConnectionManager.finishUploadConnection(this);
 75		message.setDownloadable(null);
 76		mXmppConnectionService.markMessage(message,Message.STATUS_SEND_FAILED);
 77	}
 78
 79	public void init(Message message) {
 80		this.message = message;
 81		message.setDownloadable(this);
 82		mXmppConnectionService.markMessage(message,Message.STATUS_UNSEND);
 83		this.account = message.getConversation().getAccount();
 84		this.file = mXmppConnectionService.getFileBackend().getFile(message, false);
 85		this.file.setExpectedSize(this.file.getSize());
 86
 87		if (Config.ENCRYPT_ON_HTTP_UPLOADED) {
 88			this.key = new byte[48];
 89			mXmppConnectionService.getRNG().nextBytes(this.key);
 90			this.file.setKey(this.key);
 91		}
 92
 93		Jid host = account.getXmppConnection().findDiscoItemByFeature(Xmlns.HTTP_UPLOAD);
 94		IqPacket request = mXmppConnectionService.getIqGenerator().requestHttpUploadSlot(host,file);
 95		mXmppConnectionService.sendIqPacket(account, request, new OnIqPacketReceived() {
 96			@Override
 97			public void onIqPacketReceived(Account account, IqPacket packet) {
 98				if (packet.getType() == IqPacket.TYPE.RESULT) {
 99					Element slot = packet.findChild("slot",Xmlns.HTTP_UPLOAD);
100					if (slot != null) {
101						try {
102							mGetUrl = new URL(slot.findChildContent("get"));
103							mPutUrl = new URL(slot.findChildContent("put"));
104							if (!canceled) {
105								new Thread(new FileUploader()).start();
106							}
107						} catch (MalformedURLException e) {
108							fail();
109						}
110					} else {
111						fail();
112					}
113				} else {
114					fail();
115				}
116			}
117		});
118	}
119
120	private class FileUploader implements Runnable {
121
122		@Override
123		public void run() {
124			this.upload();
125		}
126
127		private void upload() {
128			OutputStream os = null;
129			InputStream is = null;
130			HttpURLConnection connection = null;
131			try {
132				Log.d(Config.LOGTAG, "uploading to " + mPutUrl.toString());
133				connection = (HttpURLConnection) mPutUrl.openConnection();
134				connection.setRequestMethod("PUT");
135				connection.setFixedLengthStreamingMode((int) file.getExpectedSize());
136				connection.setDoOutput(true);
137				connection.connect();
138				os = connection.getOutputStream();
139				is = file.createInputStream();
140				transmitted = 0;
141				expected = file.getExpectedSize();
142				int count = -1;
143				byte[] buffer = new byte[4096];
144				while (((count = is.read(buffer)) != -1) && !canceled) {
145					transmitted += count;
146					os.write(buffer, 0, count);
147					mXmppConnectionService.updateConversationUi();
148				}
149				os.flush();
150				os.close();
151				is.close();
152				int code = connection.getResponseCode();
153				if (code == 200) {
154					Log.d(Config.LOGTAG, "finished uploading file");
155					Message.ImageParams params = message.getImageParams();
156					if (key != null) {
157						mGetUrl = new URL(mGetUrl.toString() + "#" + CryptoHelper.bytesToHex(key));
158					}
159					message.setBody(mGetUrl.toString()+"|"+String.valueOf(params.size)+"|"+String.valueOf(params.width)+"|"+String.valueOf(params.height));
160					message.setDownloadable(null);
161					message.setCounterpart(message.getConversation().getJid().toBareJid());
162					mXmppConnectionService.resendMessage(message);
163				} else {
164					fail();
165				}
166			} catch (IOException e) {
167				Log.d(Config.LOGTAG, e.getMessage());
168				fail();
169			} finally {
170				FileBackend.close(is);
171				FileBackend.close(os);
172				if (connection != null) {
173					connection.disconnect();
174				}
175			}
176		}
177	}
178}