You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by ag...@apache.org on 2013/03/27 22:01:09 UTC
android commit: [CB-1517] Properly report download progress for
GZIP-encoded resources
Updated Branches:
refs/heads/master 36c33a588 -> 282367c6d
[CB-1517] Properly report download progress for GZIP-encoded resources
Project: http://git-wip-us.apache.org/repos/asf/cordova-android/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-android/commit/282367c6
Tree: http://git-wip-us.apache.org/repos/asf/cordova-android/tree/282367c6
Diff: http://git-wip-us.apache.org/repos/asf/cordova-android/diff/282367c6
Branch: refs/heads/master
Commit: 282367c6d59bf7a74d2455c7ff7b478f2157f0a1
Parents: 36c33a5
Author: Ian Clelland <ic...@chromium.org>
Authored: Tue Mar 19 22:39:11 2013 -0400
Committer: Andrew Grieve <ag...@chromium.org>
Committed: Wed Mar 27 17:00:22 2013 -0400
----------------------------------------------------------------------
framework/src/org/apache/cordova/FileTransfer.java | 101 +++++++++++++--
1 files changed, 91 insertions(+), 10 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cordova-android/blob/282367c6/framework/src/org/apache/cordova/FileTransfer.java
----------------------------------------------------------------------
diff --git a/framework/src/org/apache/cordova/FileTransfer.java b/framework/src/org/apache/cordova/FileTransfer.java
index 75bed2c..c1ca15c 100644
--- a/framework/src/org/apache/cordova/FileTransfer.java
+++ b/framework/src/org/apache/cordova/FileTransfer.java
@@ -41,6 +41,8 @@ import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.Iterator;
+import java.util.zip.GZIPInputStream;
+import java.util.zip.Inflater;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
@@ -100,10 +102,83 @@ public class FileTransfer extends CordovaPlugin {
}
/**
+ * Adds an interface method to an InputStream to return the number of bytes
+ * read from the raw stream. This is used to track total progress against
+ * the HTTP Content-Length header value from the server.
+ */
+ private static abstract class TrackingInputStream extends FilterInputStream {
+ public TrackingInputStream(final InputStream in) {
+ super(in);
+ }
+ public abstract long getTotalRawBytesRead();
+ }
+
+ private static class ExposedGZIPInputStream extends GZIPInputStream {
+ public ExposedGZIPInputStream(final InputStream in) throws IOException {
+ super(in);
+ }
+ public Inflater getInflater() {
+ return inf;
+ }
+ }
+
+ /**
+ * Provides raw bytes-read tracking for a GZIP input stream. Reports the
+ * total number of compressed bytes read from the input, rather than the
+ * number of uncompressed bytes.
+ */
+ private static class TrackingGZIPInputStream extends TrackingInputStream {
+ private ExposedGZIPInputStream gzin;
+ public TrackingGZIPInputStream(final ExposedGZIPInputStream gzin) throws IOException {
+ super(gzin);
+ this.gzin = gzin;
+ }
+ public long getTotalRawBytesRead() {
+ return gzin.getInflater().getBytesRead();
+ }
+ }
+
+ /**
+ * Provides simple total-bytes-read tracking for an existing InputStream
+ */
+ private static class TrackingHTTPInputStream extends TrackingInputStream {
+ private long bytesRead = 0;
+ public TrackingHTTPInputStream(InputStream stream) {
+ super(stream);
+ }
+
+ private int updateBytesRead(int newBytesRead) {
+ if (newBytesRead != -1) {
+ bytesRead += newBytesRead;
+ }
+ return newBytesRead;
+ }
+
+ @Override
+ public int read() throws IOException {
+ return updateBytesRead(super.read());
+ }
+
+ @Override
+ public int read(byte[] buffer) throws IOException {
+ return updateBytesRead(super.read(buffer));
+ }
+
+ @Override
+ public int read(byte[] bytes, int offset, int count) throws IOException {
+ return updateBytesRead(super.read(bytes, offset, count));
+ }
+
+ public long getTotalRawBytesRead() {
+ return bytesRead;
+ }
+ }
+
+ /**
* Works around a bug on Android 2.3.
* http://code.google.com/p/android/issues/detail?id=14562
*/
- private static final class DoneHandlerInputStream extends FilterInputStream {
+ private static final class DoneHandlerInputStream extends TrackingHTTPInputStream {
private boolean done;
public DoneHandlerInputStream(InputStream stream) {
@@ -409,7 +484,7 @@ public class FileTransfer extends CordovaPlugin {
int responseCode = conn.getResponseCode();
Log.d(LOG_TAG, "response code: " + responseCode);
Log.d(LOG_TAG, "response headers: " + conn.getHeaderFields());
- InputStream inStream = null;
+ TrackingInputStream inStream = null;
try {
inStream = getInputStream(conn);
synchronized (context) {
@@ -485,11 +560,15 @@ public class FileTransfer extends CordovaPlugin {
}
}
- private static InputStream getInputStream(URLConnection conn) throws IOException {
+ private static TrackingInputStream getInputStream(URLConnection conn) throws IOException {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
return new DoneHandlerInputStream(conn.getInputStream());
}
- return conn.getInputStream();
+ String encoding = conn.getContentEncoding();
+ if (encoding != null && encoding.equalsIgnoreCase("gzip")) {
+ return new TrackingGZIPInputStream(new ExposedGZIPInputStream(conn.getInputStream()));
+ }
+ return new TrackingHTTPInputStream(conn.getInputStream());
}
// always verify the host - don't check for certificate
@@ -700,6 +779,9 @@ public class FileTransfer extends CordovaPlugin {
{
connection.setRequestProperty("cookie", cookie);
}
+
+ // This must be explicitly set for gzip progress tracking to work.
+ connection.setRequestProperty("Accept-Encoding", "gzip");
// Handle the other headers
if (headers != null) {
@@ -711,14 +793,15 @@ public class FileTransfer extends CordovaPlugin {
Log.d(LOG_TAG, "Download file:" + url);
FileProgressResult progress = new FileProgressResult();
- if (connection.getContentEncoding() == null) {
- // Only trust content-length header if no gzip etc
+ if (connection.getContentEncoding() == null || connection.getContentEncoding().equalsIgnoreCase("gzip")) {
+ // Only trust content-length header if we understand
+ // the encoding -- identity or gzip
progress.setLengthComputable(true);
progress.setTotal(connection.getContentLength());
}
FileOutputStream outputStream = null;
- InputStream inputStream = null;
+ TrackingInputStream inputStream = null;
try {
inputStream = getInputStream(connection);
@@ -733,12 +816,10 @@ public class FileTransfer extends CordovaPlugin {
// write bytes to file
byte[] buffer = new byte[MAX_BUFFER_SIZE];
int bytesRead = 0;
- long totalBytes = 0;
while ((bytesRead = inputStream.read(buffer)) > 0) {
outputStream.write(buffer, 0, bytesRead);
- totalBytes += bytesRead;
// Send a progress event.
- progress.setLoaded(totalBytes);
+ progress.setLoaded(inputStream.getTotalRawBytesRead());
PluginResult progressResult = new PluginResult(PluginResult.Status.OK, progress.toJSONObject());
progressResult.setKeepCallback(true);
context.sendPluginResult(progressResult);