Updated Branches:
  refs/heads/2.9.x 93b9b53ac -> 1dfbebf98

Update snapshot of FileTransfer.java to

cordova-plugin-file-transfer@9d2246e85c7f4b002218e6d231c0d452a9650cf7


Project: http://git-wip-us.apache.org/repos/asf/cordova-android/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-android/commit/57e92e8a
Tree: http://git-wip-us.apache.org/repos/asf/cordova-android/tree/57e92e8a
Diff: http://git-wip-us.apache.org/repos/asf/cordova-android/diff/57e92e8a

Branch: refs/heads/2.9.x
Commit: 57e92e8a567a3941e84754af1ce47694e594a5f6
Parents: 93b9b53
Author: Andrew Grieve <[email protected]>
Authored: Tue Oct 22 15:36:04 2013 -0400
Committer: Andrew Grieve <[email protected]>
Committed: Tue Oct 22 15:36:04 2013 -0400

----------------------------------------------------------------------
 .../src/org/apache/cordova/FileTransfer.java    | 319 ++++++++-----------
 1 file changed, 133 insertions(+), 186 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-android/blob/57e92e8a/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 1b45fef..76dae9e 100644
--- a/framework/src/org/apache/cordova/FileTransfer.java
+++ b/framework/src/org/apache/cordova/FileTransfer.java
@@ -22,19 +22,14 @@ import java.io.BufferedReader;
 import java.io.ByteArrayOutputStream;
 import java.io.Closeable;
 import java.io.File;
-import java.io.FileInputStream;
 import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
 import java.io.FilterInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.OutputStream;
-import java.io.StringWriter;
 import java.io.UnsupportedEncodingException;
 import java.net.HttpURLConnection;
-import java.net.MalformedURLException;
-import java.net.URL;
 import java.net.URLConnection;
 import java.net.URLDecoder;
 import java.security.cert.CertificateException;
@@ -52,9 +47,10 @@ import javax.net.ssl.SSLSocketFactory;
 import javax.net.ssl.TrustManager;
 import javax.net.ssl.X509TrustManager;
 
+import org.apache.cordova.CordovaResourceApi.OpenForReadResult;
 import org.apache.cordova.api.CallbackContext;
-import org.apache.cordova.api.CordovaPlugin;
 import org.apache.cordova.api.PluginResult;
+
 import org.json.JSONArray;
 import org.json.JSONException;
 import org.json.JSONObject;
@@ -64,8 +60,6 @@ import android.os.Build;
 import android.util.Log;
 import android.webkit.CookieManager;
 
-import com.squareup.okhttp.OkHttpClient;
-
 public class FileTransfer extends CordovaPlugin {
 
     private static final String LOG_TAG = "FileTransfer";
@@ -81,8 +75,6 @@ public class FileTransfer extends CordovaPlugin {
     private static HashMap<String, RequestContext> activeRequests = new 
HashMap<String, RequestContext>();
     private static final int MAX_BUFFER_SIZE = 16 * 1024;
 
-    private static OkHttpClient httpClient = new OkHttpClient();
-
     private static final class RequestContext {
         String source;
         String target;
@@ -111,20 +103,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
@@ -132,30 +124,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
@@ -174,7 +166,7 @@ public class FileTransfer extends CordovaPlugin {
         }
 
         public long getTotalRawBytesRead() {
-               return bytesRead;
+          return bytesRead;
         }
     }
 
@@ -251,6 +243,8 @@ public class FileTransfer extends CordovaPlugin {
         final JSONObject headers = args.optJSONObject(8) == null ? 
params.optJSONObject("headers") : args.optJSONObject(8);
         final String objectId = args.getString(9);
         final String httpMethod = getArgument(args, 10, "POST");
+        
+        final CordovaResourceApi resourceApi = webView.getResourceApi();
 
         Log.d(LOG_TAG, "fileKey: " + fileKey);
         Log.d(LOG_TAG, "fileName: " + fileName);
@@ -262,16 +256,20 @@ public class FileTransfer extends CordovaPlugin {
         Log.d(LOG_TAG, "objectId: " + objectId);
         Log.d(LOG_TAG, "httpMethod: " + httpMethod);
         
-        final URL url;
-        try {
-            url = new URL(target);
-        } catch (MalformedURLException e) {
+        final Uri targetUri = resourceApi.remapUri(Uri.parse(target));
+        // Accept a path or a URI for the source.
+        Uri tmpSrc = Uri.parse(source);
+        final Uri sourceUri = resourceApi.remapUri(
+            tmpSrc.getScheme() != null ? tmpSrc : Uri.fromFile(new 
File(source)));
+
+        int uriType = CordovaResourceApi.getUriType(targetUri);
+        final boolean useHttps = uriType == CordovaResourceApi.URI_TYPE_HTTPS;
+        if (uriType != CordovaResourceApi.URI_TYPE_HTTP && !useHttps) {
             JSONObject error = createFileTransferError(INVALID_URL_ERR, 
source, target, null, 0);
-            Log.e(LOG_TAG, error.toString(), e);
+            Log.e(LOG_TAG, "Unsupported URI: " + targetUri);
             callbackContext.sendPluginResult(new 
PluginResult(PluginResult.Status.IO_EXCEPTION, error));
             return;
         }
-        final boolean useHttps = url.getProtocol().equals("https");
 
         final RequestContext context = new RequestContext(source, target, 
callbackContext);
         synchronized (activeRequests) {
@@ -295,27 +293,15 @@ public class FileTransfer extends CordovaPlugin {
 
                     //------------------ CLIENT REQUEST
                     // Open a HTTP connection to the URL based on protocol
-                    if (useHttps) {
-                        // Using standard HTTPS connection. Will not allow 
self signed certificate
-                        if (!trustEveryone) {
-                            conn = (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);
-                            conn = https;
-                        }
-                    }
-                    // Return a standard HTTP connection
-                    else {
-                        conn = httpClient.open(url);
+                    conn = resourceApi.createHttpConnection(targetUri);
+                    if (useHttps && trustEveryone) {
+                        // Setup the HTTPS connection class to trust everyone
+                        HttpsURLConnection https = (HttpsURLConnection)conn;
+                        oldSocketFactory  = trustAllHosts(https);
+                        // Save the current hostnameVerifier
+                        oldHostnameVerifier = https.getHostnameVerifier();
+                        // Setup the connection not to verify hostnames
+                        https.setHostnameVerifier(DO_NOT_VERIFY);
                     }
 
                     // Allow Inputs
@@ -372,11 +358,11 @@ public class FileTransfer extends CordovaPlugin {
 
                     
                     // Get a input stream of the file on the phone
-                    InputStream sourceInputStream = getPathFromUri(source);
+                    OpenForReadResult readResult = 
resourceApi.openForRead(sourceUri);
                     
                     int stringLength = beforeDataBytes.length + 
tailParamsBytes.length;
-                    if (sourceInputStream instanceof FileInputStream) {
-                        fixedLength = (int) 
((FileInputStream)sourceInputStream).getChannel().size() + stringLength;
+                    if (readResult.length >= 0) {
+                        fixedLength = (int)readResult.length + stringLength;
                         progress.setLengthComputable(true);
                         progress.setTotal(fixedLength);
                     }
@@ -412,12 +398,12 @@ public class FileTransfer extends CordovaPlugin {
                         totalBytes += beforeDataBytes.length;
     
                         // create a buffer of maximum size
-                        int bytesAvailable = sourceInputStream.available();
+                        int bytesAvailable = 
readResult.inputStream.available();
                         int bufferSize = Math.min(bytesAvailable, 
MAX_BUFFER_SIZE);
                         byte[] buffer = new byte[bufferSize];
     
                         // read file and write it into form...
-                        int bytesRead = sourceInputStream.read(buffer, 0, 
bufferSize);
+                        int bytesRead = readResult.inputStream.read(buffer, 0, 
bufferSize);
     
                         long prevBytesRead = 0;
                         while (bytesRead > 0) {
@@ -428,9 +414,9 @@ public class FileTransfer extends CordovaPlugin {
                                 prevBytesRead = totalBytes;
                                 Log.d(LOG_TAG, "Uploaded " + totalBytes + " of 
" + fixedLength + " bytes");
                             }
-                            bytesAvailable = sourceInputStream.available();
+                            bytesAvailable = 
readResult.inputStream.available();
                             bufferSize = Math.min(bytesAvailable, 
MAX_BUFFER_SIZE);
-                            bytesRead = sourceInputStream.read(buffer, 0, 
bufferSize);
+                            bytesRead = readResult.inputStream.read(buffer, 0, 
bufferSize);
 
                             // Send a progress event.
                             progress.setLoaded(totalBytes);
@@ -444,7 +430,7 @@ public class FileTransfer extends CordovaPlugin {
                         totalBytes += tailParamsBytes.length;
                         sendStream.flush();
                     } finally {
-                        safeClose(sourceInputStream);
+                        safeClose(readResult.inputStream);
                         safeClose(sendStream);
                     }
                     context.currentOutputStream = null;
@@ -534,9 +520,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
@@ -607,7 +593,8 @@ public class FileTransfer extends CordovaPlugin {
                         body = bodyBuilder.toString();
                     }
                 }
-            } catch (IOException e) {
+            // IOException can leave connection object in a bad state, so 
catch all exceptions.
+            } catch (Throwable e) {
                 Log.w(LOG_TAG, "Error getting HTTP status code from 
connection.", e);
             }
         }
@@ -617,7 +604,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) {
@@ -642,8 +629,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
      */
@@ -662,27 +649,35 @@ 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);
 
+        final CordovaResourceApi resourceApi = webView.getResourceApi();
+
         final boolean trustEveryone = args.optBoolean(2);
         final String objectId = args.getString(3);
         final JSONObject headers = args.optJSONObject(4);
-
-        final URL url;
-        try {
-            url = new URL(source);
-        } catch (MalformedURLException e) {
+        
+        final Uri sourceUri = resourceApi.remapUri(Uri.parse(source));
+        // Accept a path or a URI for the source.
+        Uri tmpTarget = Uri.parse(target);
+        final Uri targetUri = resourceApi.remapUri(
+            tmpTarget.getScheme() != null ? tmpTarget : Uri.fromFile(new 
File(target)));
+
+        int uriType = CordovaResourceApi.getUriType(sourceUri);
+        final boolean useHttps = uriType == CordovaResourceApi.URI_TYPE_HTTPS;
+        final boolean isLocalTransfer = !useHttps && uriType != 
CordovaResourceApi.URI_TYPE_HTTP;
+        if (uriType == CordovaResourceApi.URI_TYPE_UNKNOWN) {
             JSONObject error = createFileTransferError(INVALID_URL_ERR, 
source, target, null, 0);
-            Log.e(LOG_TAG, error.toString(), e);
+            Log.e(LOG_TAG, "Unsupported URI: " + targetUri);
             callbackContext.sendPluginResult(new 
PluginResult(PluginResult.Status.IO_EXCEPTION, error));
             return;
         }
-        final boolean useHttps = url.getProtocol().equals("https");
-
-        if (!Config.isUrlWhiteListed(source)) {
+        
+        // TODO: refactor to also allow resources & content:
+        if (!isLocalTransfer && !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));
@@ -700,81 +695,75 @@ public class FileTransfer extends CordovaPlugin {
                 if (context.aborted) {
                     return;
                 }
-                URLConnection connection = null;
+                HttpURLConnection connection = null;
                 HostnameVerifier oldHostnameVerifier = null;
                 SSLSocketFactory oldSocketFactory = null;
                 File file = null;
                 PluginResult result = null;
+                TrackingInputStream inputStream = null;
 
+                OutputStream outputStream = null;
                 try {
-                    file = getFileFromPath(target);
+                    OpenForReadResult readResult = null;
+                    outputStream = resourceApi.openOutputStream(targetUri);
+
+                    file = resourceApi.mapUriToFile(targetUri);
                     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:" + sourceUri);
+
+                    FileProgressResult progress = new FileProgressResult();
+
+                    if (isLocalTransfer) {
+                        readResult = resourceApi.openForRead(sourceUri);
+                        if (readResult.length != -1) {
+                            progress.setLengthComputable(true);
+                            progress.setTotal(readResult.length);
                         }
-                        // Use our HTTPS connection that blindly trusts 
everyone.
-                        // This should only be used in debug environments
-                        else {
+                        inputStream = new 
SimpleTrackingInputStream(readResult.inputStream);
+                    } else {
+                        // connect to server
+                        // Open a HTTP connection to the URL based on protocol
+                        connection = 
resourceApi.createHttpConnection(sourceUri);
+                        if (useHttps && trustEveryone) {
                             // Setup the HTTPS connection class to trust 
everyone
-                            HttpsURLConnection https = (HttpsURLConnection) 
httpClient.open(url);
+                            HttpsURLConnection https = 
(HttpsURLConnection)connection;
                             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 {
-                          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);
-                    }
+        
+                        connection.setRequestMethod("GET");
+        
+                        // TODO: Make OkHttp use this CookieManager by default.
+                        String cookie = 
CookieManager.getInstance().getCookie(sourceUri.toString());
+                        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;
-                    
                     try {
-                        inputStream = getInputStream(connection);
-                        outputStream = new FileOutputStream(file);
                         synchronized (context) {
                             if (context.aborted) {
                                 return;
@@ -821,6 +810,7 @@ public class FileTransfer extends CordovaPlugin {
                     Log.e(LOG_TAG, error.toString(), e);
                     result = new 
PluginResult(PluginResult.Status.IO_EXCEPTION, error);
                 } finally {
+                    safeClose(outputStream);
                     synchronized (activeRequests) {
                         activeRequests.remove(objectId);
                     }
@@ -848,49 +838,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 {
-        try {
-            InputStream stream = FileHelper.getInputStreamFromUriString(path, 
cordova);
-            if (stream == null) {
-                return new FileInputStream(path);
-            } else {
-                return stream;
-            }
-        } catch (IOException e) {
-               throw new FileNotFoundException();
-        }
-    }
-
-    /**
-     * 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) {

Reply via email to