summaryrefslogtreecommitdiffstats
path: root/src/com/android/providers/downloads/DownloadThread.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/providers/downloads/DownloadThread.java')
-rw-r--r--src/com/android/providers/downloads/DownloadThread.java52
1 files changed, 39 insertions, 13 deletions
diff --git a/src/com/android/providers/downloads/DownloadThread.java b/src/com/android/providers/downloads/DownloadThread.java
index aa0190bf..c75e4193 100644
--- a/src/com/android/providers/downloads/DownloadThread.java
+++ b/src/com/android/providers/downloads/DownloadThread.java
@@ -17,6 +17,7 @@
package com.android.providers.downloads;
import static android.provider.Downloads.Impl.STATUS_BAD_REQUEST;
+import static android.provider.Downloads.Impl.STATUS_CANCELED;
import static android.provider.Downloads.Impl.STATUS_CANNOT_RESUME;
import static android.provider.Downloads.Impl.STATUS_FILE_ERROR;
import static android.provider.Downloads.Impl.STATUS_HTTP_DATA_ERROR;
@@ -143,10 +144,7 @@ public class DownloadThread implements Runnable {
mETag = info.mETag;
}
- /**
- * Push update of current delta values to provider.
- */
- public void writeToDatabase() {
+ private ContentValues buildContentValues() {
final ContentValues values = new ContentValues();
values.put(Downloads.Impl.COLUMN_URI, mUri);
@@ -162,7 +160,26 @@ public class DownloadThread implements Runnable {
values.put(Downloads.Impl.COLUMN_LAST_MODIFICATION, mSystemFacade.currentTimeMillis());
values.put(Downloads.Impl.COLUMN_ERROR_MSG, mErrorMsg);
- mContext.getContentResolver().update(mInfo.getAllDownloadsUri(), values, null, null);
+ return values;
+ }
+
+ /**
+ * Blindly push update of current delta values to provider.
+ */
+ public void writeToDatabase() {
+ mContext.getContentResolver().update(mInfo.getAllDownloadsUri(), buildContentValues(),
+ null, null);
+ }
+
+ /**
+ * Push update of current delta values to provider, asserting strongly
+ * that we haven't been paused or deleted.
+ */
+ public void writeToDatabaseOrThrow() throws StopRequestException {
+ if (mContext.getContentResolver().update(mInfo.getAllDownloadsUri(),
+ buildContentValues(), Downloads.Impl.COLUMN_DELETED + " == '0'", null) == 0) {
+ throw new StopRequestException(STATUS_CANCELED, "Download deleted or missing!");
+ }
}
}
@@ -422,12 +439,16 @@ public class DownloadThread implements Runnable {
*/
private void transferData(HttpURLConnection conn) throws StopRequestException {
- // To detect when we're really finished, we either need a length or
- // chunked encoding.
+ // To detect when we're really finished, we either need a length, closed
+ // connection, or chunked encoding.
final boolean hasLength = mInfoDelta.mTotalBytes != -1;
- final String transferEncoding = conn.getHeaderField("Transfer-Encoding");
- final boolean isChunked = "chunked".equalsIgnoreCase(transferEncoding);
- if (!hasLength && !isChunked) {
+ final boolean isConnectionClose = "close".equalsIgnoreCase(
+ conn.getHeaderField("Connection"));
+ final boolean isEncodingChunked = "chunked".equalsIgnoreCase(
+ conn.getHeaderField("Transfer-Encoding"));
+
+ final boolean finishKnown = hasLength || isConnectionClose || isEncodingChunked;
+ if (!finishKnown) {
throw new StopRequestException(
STATUS_CANNOT_RESUME, "can't know size of download, giving up");
}
@@ -666,7 +687,7 @@ public class DownloadThread implements Runnable {
/**
* Report download progress through the database if necessary.
*/
- private void updateProgress(FileDescriptor outFd) throws IOException {
+ private void updateProgress(FileDescriptor outFd) throws IOException, StopRequestException {
final long now = SystemClock.elapsedRealtime();
final long currentBytes = mInfoDelta.mCurrentBytes;
@@ -697,7 +718,7 @@ public class DownloadThread implements Runnable {
// so we can always resume based on latest database information.
outFd.sync();
- mInfoDelta.writeToDatabase();
+ mInfoDelta.writeToDatabaseOrThrow();
mLastUpdateBytes = currentBytes;
mLastUpdateTime = now;
@@ -736,7 +757,7 @@ public class DownloadThread implements Runnable {
mInfoDelta.mETag = conn.getHeaderField("ETag");
- mInfoDelta.writeToDatabase();
+ mInfoDelta.writeToDatabaseOrThrow();
// Check connectivity again now that we know the total size
checkConnectivity();
@@ -775,6 +796,10 @@ public class DownloadThread implements Runnable {
// easily resume partial downloads.
conn.setRequestProperty("Accept-Encoding", "identity");
+ // Defeat connection reuse, since otherwise servers may continue
+ // streaming large downloads after cancelled.
+ conn.setRequestProperty("Connection", "close");
+
if (resuming) {
if (mInfoDelta.mETag != null) {
conn.addRequestProperty("If-Match", mInfoDelta.mETag);
@@ -834,6 +859,7 @@ public class DownloadThread implements Runnable {
case STATUS_HTTP_DATA_ERROR:
case HTTP_UNAVAILABLE:
case HTTP_INTERNAL_ERROR:
+ case STATUS_FILE_ERROR:
return true;
default:
return false;