From 3b5e83c74f17a318162f39a2004fe33207de1f10 Mon Sep 17 00:00:00 2001 From: daniel oeh Date: Mon, 17 Mar 2014 13:02:37 +0100 Subject: [PATCH] Added authentication support to DownloadRequester and HttpDownloader --- res/values/strings.xml | 1 + .../service/download/DownloadRequest.java | 26 ++++++- .../service/download/HttpDownloader.java | 19 ++++- .../antennapod/storage/DownloadRequester.java | 77 +++++++++++++------ .../danoeh/antennapod/util/DownloadError.java | 3 +- 5 files changed, 96 insertions(+), 30 deletions(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index 4ea68d980..94d778b25 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -100,6 +100,7 @@ Unsupported Feed type Connection error Unknown host + Authentication error Cancel all downloads Download cancelled Downloads completed diff --git a/src/de/danoeh/antennapod/service/download/DownloadRequest.java b/src/de/danoeh/antennapod/service/download/DownloadRequest.java index 1f4e32e1b..320936cf1 100644 --- a/src/de/danoeh/antennapod/service/download/DownloadRequest.java +++ b/src/de/danoeh/antennapod/service/download/DownloadRequest.java @@ -8,6 +8,8 @@ public class DownloadRequest implements Parcelable { private final String destination; private final String source; private final String title; + private final String username; + private final String password; private final long feedfileId; private final int feedfileType; @@ -17,7 +19,7 @@ public class DownloadRequest implements Parcelable { protected int statusMsg; public DownloadRequest(String destination, String source, String title, - long feedfileId, int feedfileType) { + long feedfileId, int feedfileType, String username, String password) { if (destination == null) { throw new IllegalArgumentException("Destination must not be null"); } @@ -33,14 +35,28 @@ public class DownloadRequest implements Parcelable { this.title = title; this.feedfileId = feedfileId; this.feedfileType = feedfileType; + this.username = username; + this.password = password; } + public DownloadRequest(String destination, String source, String title, + long feedfileId, int feedfileType) { + this(destination, source, title, feedfileId, feedfileType, null, null); + } + private DownloadRequest(Parcel in) { destination = in.readString(); source = in.readString(); title = in.readString(); feedfileId = in.readLong(); feedfileType = in.readInt(); + if (in.dataAvail() > 0) { + username = in.readString(); + password = in.readString(); + } else { + username = null; + password = null; + } } @Override @@ -174,4 +190,12 @@ public class DownloadRequest implements Parcelable { public void setStatusMsg(int statusMsg) { this.statusMsg = statusMsg; } + + public String getUsername() { + return username; + } + + public String getPassword() { + return password; + } } diff --git a/src/de/danoeh/antennapod/service/download/HttpDownloader.java b/src/de/danoeh/antennapod/service/download/HttpDownloader.java index 1ffea19d5..4b6455343 100644 --- a/src/de/danoeh/antennapod/service/download/HttpDownloader.java +++ b/src/de/danoeh/antennapod/service/download/HttpDownloader.java @@ -8,6 +8,7 @@ import de.danoeh.antennapod.R; import de.danoeh.antennapod.util.DownloadError; import de.danoeh.antennapod.util.StorageUtils; import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; import org.apache.http.Header; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; @@ -54,6 +55,9 @@ public class HttpDownloader extends Downloader { new UsernamePasswordCredentials(parts[0], parts[1]), "UTF-8", false)); } + } else if (StringUtils.isEmpty(request.getUsername()) && request.getPassword() != null) { + httpGet.addHeader(BasicScheme.authenticate(new UsernamePasswordCredentials(request.getUsername(), + request.getPassword()), "UTF-8", false)); } HttpResponse response = httpClient.execute(httpGet); HttpEntity httpEntity = response.getEntity(); @@ -67,8 +71,16 @@ public class HttpDownloader extends Downloader { Log.d(TAG, "Response code is " + responseCode); if (responseCode != HttpURLConnection.HTTP_OK || httpEntity == null) { - onFail(DownloadError.ERROR_HTTP_DATA_ERROR, - String.valueOf(responseCode)); + final DownloadError error; + final String details; + if (responseCode == HttpURLConnection.HTTP_UNAUTHORIZED) { + error = DownloadError.ERROR_UNAUTHORIZED; + details = String.valueOf(responseCode); + } else { + error = DownloadError.ERROR_HTTP_DATA_ERROR; + details = String.valueOf(responseCode); + } + onFail(error, details); return; } @@ -132,7 +144,8 @@ public class HttpDownloader extends Downloader { "Download completed but size: " + request.getSoFar() + " does not equal expected size " + - request.getSize()); + request.getSize() + ); return; } onSuccess(); diff --git a/src/de/danoeh/antennapod/storage/DownloadRequester.java b/src/de/danoeh/antennapod/storage/DownloadRequester.java index 013162f0c..ba112b662 100644 --- a/src/de/danoeh/antennapod/storage/DownloadRequester.java +++ b/src/de/danoeh/antennapod/storage/DownloadRequester.java @@ -1,28 +1,28 @@ package de.danoeh.antennapod.storage; -import java.io.File; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -import org.apache.commons.io.FilenameUtils; -import org.apache.commons.lang3.StringUtils; - import android.content.Context; import android.content.Intent; import android.util.Log; import android.webkit.URLUtil; import de.danoeh.antennapod.AppConfig; -import de.danoeh.antennapod.feed.EventDistributor; -import de.danoeh.antennapod.feed.Feed; -import de.danoeh.antennapod.feed.FeedFile; -import de.danoeh.antennapod.feed.FeedImage; -import de.danoeh.antennapod.feed.FeedMedia; +import de.danoeh.antennapod.feed.*; import de.danoeh.antennapod.preferences.UserPreferences; import de.danoeh.antennapod.service.download.DownloadRequest; import de.danoeh.antennapod.service.download.DownloadService; import de.danoeh.antennapod.util.FileNameGenerator; import de.danoeh.antennapod.util.URLChecker; +import org.apache.commons.io.FilenameUtils; +import org.apache.commons.lang3.StringUtils; +import java.io.File; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + + +/** + * Sends download requests to the DownloadService. This class should always be used for starting downloads, + * otherwise they won't work correctly. + */ public class DownloadRequester { private static final String TAG = "DownloadRequester"; @@ -45,8 +45,34 @@ public class DownloadRequester { return downloader; } + /** + * Starts a new download with the given DownloadRequest. This method should only + * be used from outside classes if the DownloadRequest was created by the DownloadService to + * ensure that the data is valid. Use downloadFeed(), downloadImage() or downloadMedia() instead. + * + * @param context Context object for starting the DownloadService + * @param request The DownloadRequest. If another DownloadRequest with the same source URL is already stored, this method + * call will return false. + * @return True if the download request was accepted, false otherwise. + */ + public boolean download(Context context, DownloadRequest request) { + if (context == null) throw new IllegalArgumentException("context = null"); + if (request == null) throw new IllegalArgumentException("request = null"); + if (downloads.containsKey(request.getSource())) { + if (AppConfig.DEBUG) Log.i(TAG, "DownloadRequest is already stored."); + return false; + } + downloads.put(request.getSource(), request); + + Intent launchIntent = new Intent(context, DownloadService.class); + launchIntent.putExtra(DownloadService.EXTRA_REQUEST, request); + context.startService(launchIntent); + EventDistributor.getInstance().sendDownloadQueuedBroadcast(); + return true; + } + private void download(Context context, FeedFile item, File dest, - boolean overwriteIfExists) { + boolean overwriteIfExists, String username, String password) { if (!isDownloadingFile(item)) { if (!isFilenameAvailable(dest.toString()) || dest.exists()) { if (AppConfig.DEBUG) @@ -88,14 +114,9 @@ public class DownloadRequester { DownloadRequest request = new DownloadRequest(dest.toString(), item.getDownload_url(), item.getHumanReadableIdentifier(), - item.getId(), item.getTypeAsInt()); + item.getId(), item.getTypeAsInt(), username, password); - downloads.put(request.getSource(), request); - - Intent launchIntent = new Intent(context, DownloadService.class); - launchIntent.putExtra(DownloadService.EXTRA_REQUEST, request); - context.startService(launchIntent); - EventDistributor.getInstance().sendDownloadQueuedBroadcast(); + download(context, request); } else { Log.e(TAG, "URL " + item.getDownload_url() + " is already being downloaded"); @@ -124,8 +145,11 @@ public class DownloadRequester { public void downloadFeed(Context context, Feed feed) throws DownloadRequestException { if (feedFileValid(feed)) { + String username = (feed.getPreferences() != null) ? feed.getPreferences().getUsername() : null; + String password = (feed.getPreferences() != null) ? feed.getPreferences().getPassword() : null; + download(context, feed, new File(getFeedfilePath(context), - getFeedfileName(feed)), true); + getFeedfileName(feed)), true, username, password); } } @@ -133,7 +157,7 @@ public class DownloadRequester { throws DownloadRequestException { if (feedFileValid(image)) { download(context, image, new File(getImagefilePath(context), - getImagefileName(image)), true); + getImagefileName(image)), true, null, null); } } @@ -142,7 +166,8 @@ public class DownloadRequester { if (feedFileValid(feedmedia)) { download(context, feedmedia, new File(getMediafilePath(context, feedmedia), - getMediafilename(feedmedia)), false); + getMediafilename(feedmedia)), false, null, null + ); } } @@ -278,7 +303,8 @@ public class DownloadRequester { context, MEDIA_DOWNLOADPATH + FileNameGenerator.generateFileName(media.getItem() - .getFeed().getTitle()) + "/"); + .getFeed().getTitle()) + "/" + ); return externalStorage.toString(); } @@ -305,7 +331,8 @@ public class DownloadRequester { } String URLBaseFilename = URLUtil.guessFileName(media.getDownload_url(), - null, media.getMime_type());; + null, media.getMime_type()); + ; if (titleBaseFilename != "") { // Append extension diff --git a/src/de/danoeh/antennapod/util/DownloadError.java b/src/de/danoeh/antennapod/util/DownloadError.java index f7a5c23fe..1a64991a6 100644 --- a/src/de/danoeh/antennapod/util/DownloadError.java +++ b/src/de/danoeh/antennapod/util/DownloadError.java @@ -18,7 +18,8 @@ public enum DownloadError { ERROR_NOT_ENOUGH_SPACE(10, R.string.download_error_insufficient_space), ERROR_UNKNOWN_HOST(11, R.string.download_error_unknown_host), ERROR_REQUEST_ERROR(12, R.string.download_error_request_error), - ERROR_DB_ACCESS_ERROR(13, R.string.download_error_db_access); + ERROR_DB_ACCESS_ERROR(13, R.string.download_error_db_access), + ERROR_UNAUTHORIZED(14, R.string.download_error_unauthorized); private final int code; private final int resId;