package de.danoeh.antennapodsp.service.download;
import android.net.http.AndroidHttpClient;
import android.util.Log;
import de.danoeh.antennapodsp.AppConfig;
import de.danoeh.antennapodsp.PodcastApp;
import de.danoeh.antennapodsp.R;
import de.danoeh.antennapodsp.util.DownloadError;
import de.danoeh.antennapodsp.util.StorageUtils;
import org.apache.commons.io.IOUtils;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import java.io.*;
import java.net.*;
public class HttpDownloader extends Downloader {
private static final String TAG = "HttpDownloader";
private static final int BUFFER_SIZE = 8 * 1024;
public HttpDownloader(DownloadRequest request) {
super(request);
}
private URI getURIFromRequestUrl(String source) {
try {
URL url = new URL(source);
return new URI(url.getProtocol(), url.getUserInfo(), url.getHost(), url.getPort(), url.getPath(), url.getQuery(), url.getRef());
} catch (MalformedURLException e) {
throw new IllegalArgumentException(e);
} catch (URISyntaxException e) {
throw new IllegalArgumentException(e);
}
}
@Override
protected void download() {
HttpClient httpClient = AntennapodHttpClient.getHttpClient();
BufferedOutputStream out = null;
InputStream connection = null;
try {
HttpGet httpGet = new HttpGet(getURIFromRequestUrl(request.getSource()));
HttpResponse response = httpClient.execute(httpGet);
HttpEntity httpEntity = response.getEntity();
int responseCode = response.getStatusLine().getStatusCode();
Header contentEncodingHeader = response.getFirstHeader("Content-Encoding");
final boolean isGzip = contentEncodingHeader != null &&
contentEncodingHeader.getValue().equalsIgnoreCase("gzip");
if (AppConfig.DEBUG)
Log.d(TAG, "Response code is " + responseCode);
if (responseCode != HttpURLConnection.HTTP_OK || httpEntity == null) {
onFail(DownloadError.ERROR_HTTP_DATA_ERROR,
String.valueOf(responseCode));
return;
}
if (!StorageUtils.storageAvailable(PodcastApp.getInstance())) {
onFail(DownloadError.ERROR_DEVICE_NOT_FOUND, null);
return;
}
File destination = new File(request.getDestination());
if (destination.exists()) {
Log.w(TAG, "File already exists");
onFail(DownloadError.ERROR_FILE_EXISTS, null);
return;
}
connection = new BufferedInputStream(AndroidHttpClient
.getUngzippedContent(httpEntity));
out = new BufferedOutputStream(new FileOutputStream(
destination));
byte[] buffer = new byte[BUFFER_SIZE];
int count = 0;
request.setStatusMsg(R.string.download_running);
if (AppConfig.DEBUG)
Log.d(TAG, "Getting size of download");
request.setSize(httpEntity.getContentLength());
if (AppConfig.DEBUG)
Log.d(TAG, "Size is " + request.getSize());
if (request.getSize() < 0) {
request.setSize(DownloadStatus.SIZE_UNKNOWN);
}
long freeSpace = StorageUtils.getFreeSpaceAvailable();
if (AppConfig.DEBUG)
Log.d(TAG, "Free space is " + freeSpace);
if (request.getSize() != DownloadStatus.SIZE_UNKNOWN
&& request.getSize() > freeSpace) {
onFail(DownloadError.ERROR_NOT_ENOUGH_SPACE, null);
return;
}
if (AppConfig.DEBUG)
Log.d(TAG, "Starting download");
while (!cancelled
&& (count = connection.read(buffer)) != -1) {
out.write(buffer, 0, count);
request.setSoFar(request.getSoFar() + count);
request.setProgressPercent((int) (((double) request
.getSoFar() / (double) request
.getSize()) * 100));
}
if (cancelled) {
onCancelled();
} else {
out.flush();
// check if size specified in the response header is the same as the size of the
// written file. This check cannot be made if compression was used
if (!isGzip && request.getSize() != DownloadStatus.SIZE_UNKNOWN &&
request.getSoFar() != request.getSize()) {
onFail(DownloadError.ERROR_IO_ERROR,
"Download completed but size: " +
request.getSoFar() +
" does not equal expected size " +
request.getSize());
return;
}
onSuccess();
}
} catch (IllegalArgumentException e) {
e.printStackTrace();
onFail(DownloadError.ERROR_MALFORMED_URL, e.getMessage());
} catch (SocketTimeoutException e) {
e.printStackTrace();
onFail(DownloadError.ERROR_CONNECTION_ERROR, e.getMessage());
} catch (UnknownHostException e) {
e.printStackTrace();
onFail(DownloadError.ERROR_UNKNOWN_HOST, e.getMessage());
} catch (IOException e) {
e.printStackTrace();
onFail(DownloadError.ERROR_IO_ERROR, e.getMessage());
} catch (NullPointerException e) {
// might be thrown by connection.getInputStream()
e.printStackTrace();
onFail(DownloadError.ERROR_CONNECTION_ERROR, request.getSource());
} finally {
IOUtils.closeQuietly(out);
AntennapodHttpClient.cleanup();
}
}
private void onSuccess() {
if (AppConfig.DEBUG)
Log.d(TAG, "Download was successful");
result.setSuccessful();
}
private void onFail(DownloadError reason, String reasonDetailed) {
if (AppConfig.DEBUG) {
Log.d(TAG, "Download failed");
}
result.setFailed(reason, reasonDetailed);
cleanup();
}
private void onCancelled() {
if (AppConfig.DEBUG)
Log.d(TAG, "Download was cancelled");
result.setCancelled();
cleanup();
}
/**
* Deletes unfinished downloads.
*/
private void cleanup() {
if (request.getDestination() != null) {
File dest = new File(request.getDestination());
if (dest.exists()) {
boolean rc = dest.delete();
if (AppConfig.DEBUG)
Log.d(TAG, "Deleted file " + dest.getName() + "; Result: "
+ rc);
} else {
if (AppConfig.DEBUG)
Log.d(TAG, "cleanup() didn't delete file: does not exist.");
}
}
}
}