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/07/10 21:14:39 UTC

git commit: Use UriResolvers in FileTransfer. Fixes mobile-spec test where source is a file:// URL.

Updated Branches:
  refs/heads/master e4559a21d -> f1c774938


Use UriResolvers in FileTransfer. Fixes mobile-spec test where source is a file:// URL.


Project: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/commit/f1c77493
Tree: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/tree/f1c77493
Diff: http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/diff/f1c77493

Branch: refs/heads/master
Commit: f1c774938289b4d9a34b89acd45edf2955f78d69
Parents: e4559a2
Author: Andrew Grieve <ag...@chromium.org>
Authored: Wed Jul 10 15:14:00 2013 -0400
Committer: Andrew Grieve <ag...@chromium.org>
Committed: Wed Jul 10 15:14:00 2013 -0400

----------------------------------------------------------------------
 src/android/FileTransfer.java | 255 ++++++++++++++++---------------------
 1 file changed, 113 insertions(+), 142 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-plugin-file-transfer/blob/f1c77493/src/android/FileTransfer.java
----------------------------------------------------------------------
diff --git a/src/android/FileTransfer.java b/src/android/FileTransfer.java
index c24f73d..59a3f5c 100644
--- a/src/android/FileTransfer.java
+++ b/src/android/FileTransfer.java
@@ -56,10 +56,12 @@ import org.apache.cordova.Config;
 import org.apache.cordova.CallbackContext;
 import org.apache.cordova.CordovaPlugin;
 import org.apache.cordova.PluginResult;
+import org.apache.cordova.UriResolver;
 import org.json.JSONArray;
 import org.json.JSONException;
 import org.json.JSONObject;
 
+import android.content.ContentResolver;
 import android.net.Uri;
 import android.os.Build;
 import android.util.Log;
@@ -112,20 +114,20 @@ public class FileTransfer extends CordovaPlugin {
      * the HTTP Content-Length header value from the server.
      */
     private static abstract class TrackingInputStream extends FilterInputStream {
-    	public TrackingInputStream(final InputStream in) {
-    		super(in);
-    	}
+      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;
-	    }
-	}
+      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
@@ -133,30 +135,30 @@ public class FileTransfer extends CordovaPlugin {
      * 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();
-	    }
-	}
+      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 static class SimpleTrackingInputStream extends TrackingInputStream {
         private long bytesRead = 0;
-        public TrackingHTTPInputStream(InputStream stream) {
+        public SimpleTrackingInputStream(InputStream stream) {
             super(stream);
         }
 
         private int updateBytesRead(int newBytesRead) {
-        	if (newBytesRead != -1) {
-        		bytesRead += newBytesRead;
-        	}
-        	return newBytesRead;
+          if (newBytesRead != -1) {
+            bytesRead += newBytesRead;
+          }
+          return newBytesRead;
         }
 
         @Override
@@ -175,7 +177,7 @@ public class FileTransfer extends CordovaPlugin {
         }
 
         public long getTotalRawBytesRead() {
-        	return bytesRead;
+          return bytesRead;
         }
     }
 
@@ -373,7 +375,7 @@ public class FileTransfer extends CordovaPlugin {
 
                     
                     // Get a input stream of the file on the phone
-                    InputStream sourceInputStream = getPathFromUri(source);
+                    InputStream sourceInputStream = webView.resolveUri(Uri.parse(source)).getInputStream();
                     
                     int stringLength = beforeDataBytes.length + tailParamsBytes.length;
                     if (sourceInputStream instanceof FileInputStream) {
@@ -535,9 +537,9 @@ public class FileTransfer extends CordovaPlugin {
     private static TrackingInputStream getInputStream(URLConnection conn) throws IOException {
         String encoding = conn.getContentEncoding();
         if (encoding != null && encoding.equalsIgnoreCase("gzip")) {
-        	return new TrackingGZIPInputStream(new ExposedGZIPInputStream(conn.getInputStream()));
+          return new TrackingGZIPInputStream(new ExposedGZIPInputStream(conn.getInputStream()));
         }
-        return new TrackingHTTPInputStream(conn.getInputStream());
+        return new SimpleTrackingInputStream(conn.getInputStream());
     }
 
     // always verify the host - don't check for certificate
@@ -618,7 +620,7 @@ public class FileTransfer extends CordovaPlugin {
 
         /**
         * Create an error object based on the passed in errorCode
-        * @param errorCode 	the error
+        * @param errorCode      the error
         * @return JSONObject containing the error
         */
     private static JSONObject createFileTransferError(int errorCode, String source, String target, String body, Integer httpStatus) {
@@ -643,8 +645,8 @@ public class FileTransfer extends CordovaPlugin {
 
     /**
      * Convenience method to read a parameter from the list of JSON args.
-     * @param args			the args passed to the Plugin
-     * @param position		the position to retrieve the arg from
+     * @param args                      the args passed to the Plugin
+     * @param position          the position to retrieve the arg from
      * @param defaultString the default to be used if the arg does not exist
      * @return String with the retrieved value
      */
@@ -663,7 +665,7 @@ public class FileTransfer extends CordovaPlugin {
      * Downloads a file form a given URL and saves it to the specified directory.
      *
      * @param source        URL of the server to receive the file
-     * @param target      	Full path of the file on the file system
+     * @param target            Full path of the file on the file system
      */
     private void download(final String source, final String target, JSONArray args, CallbackContext callbackContext) throws JSONException {
         Log.d(LOG_TAG, "download " + source + " to " +  target);
@@ -681,9 +683,15 @@ public class FileTransfer extends CordovaPlugin {
             callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, error));
             return;
         }
-        final boolean useHttps = url.getProtocol().equals("https");
+        final String sourceProtocol = url.getProtocol();
+        final boolean useHttps = "https".equals(sourceProtocol);
+        final boolean useResolvers =
+                ContentResolver.SCHEME_FILE.equals(sourceProtocol) ||
+                ContentResolver.SCHEME_CONTENT.equals(sourceProtocol) ||
+                ContentResolver.SCHEME_ANDROID_RESOURCE.equals(sourceProtocol);
 
-        if (!Config.isUrlWhiteListed(source)) {
+        // TODO: refactor to also allow resources & content:
+        if (!useResolvers && !Config.isUrlWhiteListed(source)) {
             Log.w(LOG_TAG, "Source URL is not in white list: '" + source + "'");
             JSONObject error = createFileTransferError(CONNECTION_ERR, source, target, null, 401);
             callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.IO_EXCEPTION, error));
@@ -708,74 +716,85 @@ public class FileTransfer extends CordovaPlugin {
                 PluginResult result = null;
 
                 try {
-                    file = getFileFromPath(target);
+                    UriResolver sourceResolver = null;
+                    UriResolver targetResolver = webView.resolveUri(Uri.parse(target));
+                    TrackingInputStream inputStream = null;
+
+                    file = targetResolver.getLocalFile();
                     context.targetFile = file;
-                    // create needed directories
-                    file.getParentFile().mkdirs();
-        
-                    // connect to server
-                    // Open a HTTP connection to the URL based on protocol
-                    if (useHttps) {
-                        // Using standard HTTPS connection. Will not allow self signed certificate
-                        if (!trustEveryone) {
-                            connection = (HttpsURLConnection) httpClient.open(url);
+                    
+                    Log.d(LOG_TAG, "Download file:" + url);
+
+                    FileProgressResult progress = new FileProgressResult();
+
+                    if (useResolvers) {
+                        sourceResolver = webView.resolveUri(Uri.parse(source));
+                        long len = sourceResolver.computeLength();
+                        if (len != -1) {
+                            progress.setLengthComputable(true);
+                            progress.setTotal(len);
                         }
-                        // Use our HTTPS connection that blindly trusts everyone.
-                        // This should only be used in debug environments
+                        inputStream = new SimpleTrackingInputStream(sourceResolver.getInputStream());
+                    } else {
+                        // connect to server
+                        // Open a HTTP connection to the URL based on protocol
+                        if (useHttps) {
+                            // Using standard HTTPS connection. Will not allow self signed certificate
+                            if (!trustEveryone) {
+                                connection = (HttpsURLConnection) httpClient.open(url);
+                            }
+                            // Use our HTTPS connection that blindly trusts everyone.
+                            // This should only be used in debug environments
+                            else {
+                                // Setup the HTTPS connection class to trust everyone
+                                HttpsURLConnection https = (HttpsURLConnection) httpClient.open(url);
+                                oldSocketFactory = trustAllHosts(https);
+                                // Save the current hostnameVerifier
+                                oldHostnameVerifier = https.getHostnameVerifier();
+                                // Setup the connection not to verify hostnames
+                                https.setHostnameVerifier(DO_NOT_VERIFY);
+                                connection = https;
+                            }
+                        }
+                        // Return a standard HTTP connection
                         else {
-                            // Setup the HTTPS connection class to trust everyone
-                            HttpsURLConnection https = (HttpsURLConnection) httpClient.open(url);
-                            oldSocketFactory = trustAllHosts(https);
-                            // Save the current hostnameVerifier
-                            oldHostnameVerifier = https.getHostnameVerifier();
-                            // Setup the connection not to verify hostnames
-                            https.setHostnameVerifier(DO_NOT_VERIFY);
-                            connection = https;
+                              connection = httpClient.open(url);
                         }
-                    }
-                    // Return a standard HTTP connection
-                    else {
-                          connection = httpClient.open(url);
-
-                    }
-    
-                    if (connection instanceof HttpURLConnection) {
-                        ((HttpURLConnection)connection).setRequestMethod("GET");
-                    }
-    
-                    //Add cookie support
-                    String cookie = CookieManager.getInstance().getCookie(source);
-                    if(cookie != null)
-                    {
-                        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) {
-                        addHeadersToRequest(connection, headers);
-                    }
+        
+                        if (connection instanceof HttpURLConnection) {
+                            ((HttpURLConnection)connection).setRequestMethod("GET");
+                        }
+        
+                        //Add cookie support
+                        String cookie = CookieManager.getInstance().getCookie(source);
+                        if(cookie != null)
+                        {
+                            connection.setRequestProperty("cookie", cookie);
+                        }
+                        
+                        // This must be explicitly set for gzip progress tracking to work.
+                        connection.setRequestProperty("Accept-Encoding", "gzip");
     
-                    connection.connect();
+                        // Handle the other headers
+                        if (headers != null) {
+                            addHeadersToRequest(connection, headers);
+                        }
+        
+                        connection.connect();
     
-                    Log.d(LOG_TAG, "Download file:" + url);
-
-                    FileProgressResult progress = new FileProgressResult();
-                    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());
+                        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());
+                        }
+                        inputStream = getInputStream(connection);
                     }
                     
-                    FileOutputStream outputStream = null;
-                    TrackingInputStream inputStream = null;
+                    OutputStream outputStream = null;
                     
                     try {
-                        inputStream = getInputStream(connection);
-                        outputStream = new FileOutputStream(file);
+                        outputStream = targetResolver.getOutputStream();
                         synchronized (context) {
                             if (context.aborted) {
                                 return;
@@ -849,54 +868,6 @@ public class FileTransfer extends CordovaPlugin {
     }
 
     /**
-     * Get an input stream based on file path or content:// uri
-     *
-     * @param path foo
-     * @return an input stream
-     * @throws FileNotFoundException
-     */
-    private InputStream getPathFromUri(String path) throws FileNotFoundException {
-        if (path.startsWith("content:")) {
-            Uri uri = Uri.parse(path);
-            return cordova.getActivity().getContentResolver().openInputStream(uri);
-        }
-        else if (path.startsWith("file://")) {
-            int question = path.indexOf("?");
-            if (question == -1) {
-                return new FileInputStream(path.substring(7));
-            } else {
-                return new FileInputStream(path.substring(7, question));
-            }
-        }
-        else {
-            return new FileInputStream(path);
-        }
-    }
-
-    /**
-     * Get a File object from the passed in path
-     *
-     * @param path file path
-     * @return file object
-     */
-    private File getFileFromPath(String path) throws FileNotFoundException {
-        File file;
-        String prefix = "file://";
-
-        if (path.startsWith(prefix)) {
-            file = new File(path.substring(prefix.length()));
-        } else {
-            file = new File(path);
-        }
-
-        if (file.getParent() == null) {
-            throw new FileNotFoundException();
-        }
-
-        return file;
-    }
-
-    /**
      * Abort an ongoing upload or download.
      */
     private void abort(String objectId) {