Merge branch 'dev' (early part)

Conflicts:
	RELEASENOTES.md
	plugin.xml
diff --git a/NOTICE b/NOTICE
new file mode 100644
index 0000000..46fed23
--- /dev/null
+++ b/NOTICE
@@ -0,0 +1,8 @@
+Apache Cordova
+Copyright 2012 The Apache Software Foundation
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+
+This product includes a copy of OkHttp from:
+https://github.com/square/okhttp
diff --git a/RELEASENOTES.md b/RELEASENOTES.md
index 537f114..34da2ff 100644
--- a/RELEASENOTES.md
+++ b/RELEASENOTES.md
@@ -57,3 +57,14 @@
 * CB-5658 Delete stale snapshot of plugin docs
 * Remove @1 designation from file plugin dependency until pushed to npm
 * CB-5466: Update to work with filesystem URLs
+
+### 0.4.2 (Feb 28, 2014)
+* CB-6106 Ensure that nativeURL is used by file transfer download
+* iOS: Fix default value for trustAllHosts on iOS (YES->NO)
+* CB-6059 iOS: Stop FileTransfer.download doing IO on the UI thread.
+* CB-5588 iOS: Add response headers to upload result
+* CB-2190 iOS: Make backgroundTaskId apply to downloads as well. Move backgroundTaskId to the delegate.
+* CB-6050 Android: Use instance method on actual file plugin object to get FileEntry to return on download
+* CB-6000 Android: Nginx rejects Content-Type without a space before "boundary".
+* CB-4907 Android: Close stream when we're finished with it
+* CB-6022 Add backwards-compatibility notes to doc
diff --git a/doc/index.md b/doc/index.md
index 2c53c0a..eb4db58 100644
--- a/doc/index.md
+++ b/doc/index.md
@@ -58,7 +58,7 @@
 
 __Parameters__:
 
-- __filePath__: Full path of the file on the device.
+- __fileURL__: Filesystem URL representing the file on the device. For backwards compatibility, this can also be the full path of the file on the device. (See [Backwards Compatibility Notes] below)
 
 - __server__: URL of the server to receive the file, as encoded by `encodeURI()`.
 
@@ -78,7 +78,8 @@
 
 ### Example
 
-    // !! Assumes variable fileURI contains a valid URI to a text file on the device
+    // !! Assumes variable fileURL contains a valid URL to a text file on the device,
+    //    for example, cdvfile://localhost/persistent/path/to/file.txt
 
     var win = function (r) {
         console.log("Code = " + r.responseCode);
@@ -94,7 +95,7 @@
 
     var options = new FileUploadOptions();
     options.fileKey = "file";
-    options.fileName = fileURI.substr(fileURI.lastIndexOf('/') + 1);
+    options.fileName = fileURL.substr(fileURL.lastIndexOf('/') + 1);
     options.mimeType = "text/plain";
 
     var params = {};
@@ -104,7 +105,7 @@
     options.params = params;
 
     var ft = new FileTransfer();
-    ft.upload(fileURI, encodeURI("http://some.server.com/upload.php"), win, fail, options);
+    ft.upload(fileURL, encodeURI("http://some.server.com/upload.php"), win, fail, options);
 
 ### Example with Upload Headers and Progress Events (Android and iOS only)
 
@@ -124,7 +125,7 @@
 
     var options = new FileUploadOptions();
     options.fileKey="file";
-    options.fileName=fileURI.substr(fileURI.lastIndexOf('/')+1);
+    options.fileName=fileURL.substr(fileURL.lastIndexOf('/')+1);
     options.mimeType="text/plain";
 
     var headers={'headerParam':'headerValue'};
@@ -139,7 +140,7 @@
           loadingStatus.increment();
         }
     };
-    ft.upload(fileURI, uri, win, fail, options);
+    ft.upload(fileURL, uri, win, fail, options);
 
 ## FileUploadResult
 
@@ -154,6 +155,9 @@
 
 - __response__: The HTTP response returned by the server. (DOMString)
 
+- __headers__: The HTTP response headers by the server. (Object)
+  - Currently supported on iOS only.
+
 ### iOS Quirks
 
 - Does not support `responseCode` or `bytesSent`.
@@ -165,7 +169,7 @@
 
 - __source__: URL of the server to download the file, as encoded by `encodeURI()`.
 
-- __target__: Full path of the file on the device.
+- __target__: Filesystem url representing the file on the device. For backwards compatibility, this can also be the full path of the file on the device. (See [Backwards Compatibility Notes] below)
 
 - __successCallback__: A callback that is passed  a `FileEntry` object. _(Function)_
 
@@ -177,14 +181,15 @@
 
 ### Example
 
-    // !! Assumes filePath is a valid path on the device
+    // !! Assumes variable fileURL contains a valid URL to a path on the device,
+    //    for example, cdvfile://localhost/persistent/path/to/downloads/
 
     var fileTransfer = new FileTransfer();
     var uri = encodeURI("http://some.server.com/download.php");
 
     fileTransfer.download(
         uri,
-        filePath,
+        fileURL,
         function(entry) {
             console.log("download complete: " + entry.fullPath);
         },
@@ -207,7 +212,8 @@
 
 ### Example
 
-    // !! Assumes variable fileURI contains a valid URI to a text file on the device
+    // !! Assumes variable fileURL contains a valid URL to a text file on the device,
+    //    for example, cdvfile://localhost/persistent/path/to/file.txt
 
     var win = function(r) {
         console.log("Should not be called.");
@@ -226,7 +232,7 @@
     options.mimeType="image/jpeg";
 
     var ft = new FileTransfer();
-    ft.upload(fileURI, encodeURI("http://some.server.com/upload.php"), win, fail, options);
+    ft.upload(fileURL, encodeURI("http://some.server.com/upload.php"), win, fail, options);
     ft.abort();
 
 
@@ -238,9 +244,9 @@
 
 - __code__: One of the predefined error codes listed below. (Number)
 
-- __source__: URI to the source. (String)
+- __source__: URL to the source. (String)
 
-- __target__: URI to the target. (String)
+- __target__: URL to the target. (String)
 
 - __http_status__: HTTP status code.  This attribute is only available when a response code is received from the HTTP connection. (Number)
 
@@ -251,3 +257,21 @@
 - `FileTransferError.CONNECTION_ERR`
 - `FileTransferError.ABORT_ERR`
 
+## Backwards Compatibility Notes
+
+Previous versions of this plugin would only accept device-absolute-file-paths as the source for uploads, or as the target for downloads. These paths would typically be of the form
+
+    /var/mobile/Applications/<application UUID>/Documents/path/to/file  (iOS)
+    /storage/emulated/0/path/to/file                                    (Android)
+
+For backwards compatibility, these paths are still accepted, and if your application has recorded paths like these in persistent storage, then they can continue to be used.
+
+These paths were previously exposed in the `fullPath` property of `FileEntry` and `DirectoryEntry` objects returned by the File plugin. New versions of the File plugin, however, no longer expose these paths to JavaScript.
+
+If you are upgrading to a new (1.0.0 or newer) version of File, and you have previously been using `entry.fullPath` as arguments to `download()` or `upload()`, then you will need to change your code to use filesystem URLs instead.
+
+`FileEntry.toURL()` and `DirectoryEntry.toURL()` return a filesystem URL of the form
+
+    cdvfile://localhost/persistent/path/to/file
+
+which can be used in place of the absolute file path in both `download()` and `upload()` methods.
diff --git a/plugin.xml b/plugin.xml
index 4b039fb..30e9588 100644
--- a/plugin.xml
+++ b/plugin.xml
@@ -2,7 +2,7 @@
 <plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
     xmlns:android="http://schemas.android.com/apk/res/android"
     id="org.apache.cordova.file-transfer"
-    version="0.4.1">
+    version="0.4.2">
     <name>File Transfer</name>
     <description>Cordova File Transfer Plugin</description>
     <license>Apache 2.0</license>
@@ -11,7 +11,7 @@
     <issue>https://issues.apache.org/jira/browse/CB/component/12320650</issue>
 
     <!-- dependency id="org.apache.cordova.file@1" /-->
-    <dependency id="org.apache.cordova.file" />
+    <dependency id="org.apache.cordova.file" version="1.0.1" />
 
     <js-module src="www/FileTransferError.js" name="FileTransferError">
         <clobbers target="window.FileTransferError" />
diff --git a/src/android/FileTransfer.java b/src/android/FileTransfer.java
index 079cd91..e370c5f 100644
--- a/src/android/FileTransfer.java
+++ b/src/android/FileTransfer.java
@@ -315,7 +315,7 @@
 
                     // Use a post method.
                     conn.setRequestMethod(httpMethod);
-                    conn.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + BOUNDARY);
+                    conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY);
 
                     // Set the cookies on the response
                     String cookie = CookieManager.getInstance().getCookie(target);
@@ -582,15 +582,19 @@
                     if(err != null)
                     {
                         BufferedReader reader = new BufferedReader(new InputStreamReader(err, "UTF-8"));
-                        String line = reader.readLine();
-                        while(line != null)
-                        {
-                            bodyBuilder.append(line);
-                            line = reader.readLine();
-                            if(line != null)
-                                bodyBuilder.append('\n');
+                        try {
+                            String line = reader.readLine();
+                            while(line != null) {
+                                bodyBuilder.append(line);
+                                line = reader.readLine();
+                                if(line != null) {
+                                    bodyBuilder.append('\n');
+                                }
+                            }
+                            body = bodyBuilder.toString();
+                        } finally {
+                            reader.close();
                         }
-                        body = bodyBuilder.toString();
                     }
                 }
             // IOException can leave connection object in a bad state, so catch all exceptions.
@@ -793,9 +797,21 @@
                     Log.d(LOG_TAG, "Saved file: " + target);
     
                     // create FileEntry object
-                    JSONObject fileEntry = FileUtils.getEntry(file);
+                    FileUtils filePlugin = (FileUtils)webView.pluginManager.getPlugin("File");
+                    if (filePlugin != null) {
+                        JSONObject fileEntry = filePlugin.getEntryForFile(file);
+                        if (fileEntry != null) {
+                            result = new PluginResult(PluginResult.Status.OK, fileEntry);
+                        } else {
+                            JSONObject error = createFileTransferError(CONNECTION_ERR, source, target, connection);
+                            Log.e(LOG_TAG, "File plugin cannot represent download path");
+                            result = new PluginResult(PluginResult.Status.IO_EXCEPTION, error);
+                        }
+                    } else {
+                        Log.e(LOG_TAG, "File plugin not found; cannot save downloaded file");
+                        result = new PluginResult(PluginResult.Status.ERROR, "File plugin not found; cannot save downloaded file");
+                    }
                     
-                    result = new PluginResult(PluginResult.Status.OK, fileEntry);
                 } catch (FileNotFoundException e) {
                     JSONObject error = createFileTransferError(FILE_NOT_FOUND_ERR, source, target, connection);
                     Log.e(LOG_TAG, error.toString(), e);
diff --git a/src/ios/CDVFileTransfer.h b/src/ios/CDVFileTransfer.h
index aa1cf9e..aea9b2d 100644
--- a/src/ios/CDVFileTransfer.h
+++ b/src/ios/CDVFileTransfer.h
@@ -19,6 +19,7 @@
 
 #import <Foundation/Foundation.h>
 #import <Cordova/CDVPlugin.h>
+#import "CDVFile.h"
 
 enum CDVFileTransferError {
     FILE_NOT_FOUND_ERR = 1,
@@ -52,8 +53,8 @@
                                       AndTarget:(NSString*)target
                                   AndHttpStatus:(int)httpStatus
                                         AndBody:(NSString*)body;
+@property (nonatomic, strong) NSOperationQueue* queue;
 @property (readonly) NSMutableDictionary* activeTransfers;
-@property (nonatomic, assign) UIBackgroundTaskIdentifier backgroundTaskID;
 @end
 
 @class CDVFileTransferEntityLengthRequest;
@@ -64,6 +65,8 @@
 - (void)cancelTransfer:(NSURLConnection*)connection;
 
 @property (strong) NSMutableData* responseData; // atomic
+@property (nonatomic, strong) NSDictionary* responseHeaders;
+@property (nonatomic, assign) UIBackgroundTaskIdentifier backgroundTaskID;
 @property (nonatomic, strong) CDVFileTransfer* command;
 @property (nonatomic, assign) CDVFileTransferDirection direction;
 @property (nonatomic, strong) NSURLConnection* connection;
@@ -79,5 +82,6 @@
 @property (nonatomic, assign) BOOL trustAllHosts;
 @property (strong) NSFileHandle* targetFileHandle;
 @property (nonatomic, strong) CDVFileTransferEntityLengthRequest* entityLengthRequest;
+@property (nonatomic, strong) CDVFile *filePlugin;
 
 @end;
diff --git a/src/ios/CDVFileTransfer.m b/src/ios/CDVFileTransfer.m
index 1ae0730..f19bece 100644
--- a/src/ios/CDVFileTransfer.m
+++ b/src/ios/CDVFileTransfer.m
@@ -19,7 +19,6 @@
 
 #import <Cordova/CDV.h>
 #import "CDVFileTransfer.h"
-#import "CDVFile.h"
 #import "CDVLocalFilesystem.h"
 
 #import <AssetsLibrary/ALAsset.h>
@@ -27,8 +26,6 @@
 #import <AssetsLibrary/ALAssetsLibrary.h>
 #import <CFNetwork/CFNetwork.h>
 
-extern CDVFile *filePlugin;
-
 @interface CDVFileTransfer ()
 // Sets the requests headers for the request.
 - (void)applyRequestHeaders:(NSDictionary*)headers toRequest:(NSMutableURLRequest*)req;
@@ -75,6 +72,10 @@
 @implementation CDVFileTransfer
 @synthesize activeTransfers;
 
+- (void)pluginInitialize {
+    activeTransfers = [[NSMutableDictionary alloc] init];
+}
+
 - (NSString*)escapePathComponentForUrlString:(NSString*)urlString
 {
     NSRange schemeAndHostRange = [urlString rangeOfString:@"://.*?/" options:NSRegularExpressionSearch];
@@ -220,12 +221,6 @@
         CFStreamCreateBoundPair(NULL, &readStream, &writeStream, kStreamBufferSize);
         [req setHTTPBodyStream:CFBridgingRelease(readStream)];
 
-        self.backgroundTaskID = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
-                [[UIApplication sharedApplication] endBackgroundTask:self.backgroundTaskID];
-                self.backgroundTaskID = UIBackgroundTaskInvalid;
-                NSLog(@"Background task to upload media finished.");
-            }];
-
         [self.commandDelegate runInBackground:^{
             if (CFWriteStreamOpen(writeStream)) {
                 NSData* chunks[] = {postBodyBeforeFile, fileData, postBodyAfterFile};
@@ -255,7 +250,7 @@
 {
     NSString* source = [command.arguments objectAtIndex:0];
     NSString* server = [command.arguments objectAtIndex:1];
-    BOOL trustAllHosts = [[command.arguments objectAtIndex:6 withDefault:[NSNumber numberWithBool:YES]] boolValue]; // allow self-signed certs
+    BOOL trustAllHosts = [[command.arguments objectAtIndex:6 withDefault:[NSNumber numberWithBool:NO]] boolValue]; // allow self-signed certs
     NSString* objectId = [command.arguments objectAtIndex:9];
 
     CDVFileTransferDelegate* delegate = [[CDVFileTransferDelegate alloc] init];
@@ -267,6 +262,7 @@
     delegate.source = source;
     delegate.target = server;
     delegate.trustAllHosts = trustAllHosts;
+    delegate.filePlugin = [self.commandDelegate getCommandInstance:@"File"];
 
     return delegate;
 }
@@ -282,7 +278,7 @@
     if (sourceURL) {
         // Try to get a CDVFileSystem which will handle this file.
         // This requires talking to the current CDVFile plugin.
-        fs = [filePlugin filesystemForURL:sourceURL];
+        fs = [[self.commandDelegate getCommandInstance:@"File"] filesystemForURL:sourceURL];
     }
     if (fs) {
         [fs readFileAtURL:sourceURL start:0 end:-1 callback:^(NSData *fileData, NSString *mimeType, CDVFileError err) {
@@ -333,25 +329,34 @@
         return;
     }
     CDVFileTransferDelegate* delegate = [self delegateForUploadCommand:command];
-    [NSURLConnection connectionWithRequest:req delegate:delegate];
-
-    if (activeTransfers == nil) {
-        activeTransfers = [[NSMutableDictionary alloc] init];
+    delegate.connection = [[NSURLConnection alloc] initWithRequest:req delegate:delegate startImmediately:NO];
+    if (self.queue == nil) {
+        self.queue = [[NSOperationQueue alloc] init];
     }
+    [delegate.connection setDelegateQueue:self.queue];
 
-    [activeTransfers setObject:delegate forKey:delegate.objectId];
+    // sets a background task ID for the transfer object.
+    delegate.backgroundTaskID = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
+        [delegate cancelTransfer:delegate.connection];
+    }];
+
+    @synchronized (activeTransfers) {
+        activeTransfers[delegate.objectId] = delegate;
+    }
+    [delegate.connection start];
 }
 
 - (void)abort:(CDVInvokedUrlCommand*)command
 {
     NSString* objectId = [command.arguments objectAtIndex:0];
 
-    CDVFileTransferDelegate* delegate = [activeTransfers objectForKey:objectId];
-
-    if (delegate != nil) {
-        [delegate cancelTransfer:delegate.connection];
-        CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:[self createFileTransferError:CONNECTION_ABORTED AndSource:delegate.source AndTarget:delegate.target]];
-        [self.commandDelegate sendPluginResult:result callbackId:delegate.callbackId];
+    @synchronized (activeTransfers) {
+        CDVFileTransferDelegate* delegate = activeTransfers[objectId];
+        if (delegate != nil) {
+            [delegate cancelTransfer:delegate.connection];
+            CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:[self createFileTransferError:CONNECTION_ABORTED AndSource:delegate.source AndTarget:delegate.target]];
+            [self.commandDelegate sendPluginResult:result callbackId:delegate.callbackId];
+        }
     }
 }
 
@@ -360,7 +365,7 @@
     DLog(@"File Transfer downloading file...");
     NSString* source = [command.arguments objectAtIndex:0];
     NSString* target = [command.arguments objectAtIndex:1];
-    BOOL trustAllHosts = [[command.arguments objectAtIndex:2 withDefault:[NSNumber numberWithBool:YES]] boolValue]; // allow self-signed certs
+    BOOL trustAllHosts = [[command.arguments objectAtIndex:2 withDefault:[NSNumber numberWithBool:NO]] boolValue]; // allow self-signed certs
     NSString* objectId = [command.arguments objectAtIndex:3];
     NSDictionary* headers = [command.arguments objectAtIndex:4 withDefault:nil];
 
@@ -374,7 +379,7 @@
          * Check here to see if it looks like the user passed in a raw filesystem path. (Perhaps they had the path saved, and were previously using it with the old version of File). If so, normalize it by removing empty path segments, and check with File to see if any of the installed filesystems will handle it. If so, then we will end up with a filesystem url to use for the remainder of this operation.
          */
         target = [target stringByReplacingOccurrencesOfString:@"//" withString:@"/"];
-        targetURL = [filePlugin fileSystemURLforLocalPath:target].url;
+        targetURL = [[self.commandDelegate getCommandInstance:@"File"] fileSystemURLforLocalPath:target].url;
     } else {
         targetURL = [NSURL URLWithString:target];
     }
@@ -410,14 +415,23 @@
     delegate.target = [targetURL absoluteString];
     delegate.targetURL = targetURL;
     delegate.trustAllHosts = trustAllHosts;
+    delegate.filePlugin = [self.commandDelegate getCommandInstance:@"File"];
+    delegate.backgroundTaskID = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
+        [delegate cancelTransfer:delegate.connection];
+    }];
 
-    delegate.connection = [NSURLConnection connectionWithRequest:req delegate:delegate];
+    delegate.connection = [[NSURLConnection alloc] initWithRequest:req delegate:delegate startImmediately:NO];
 
-    if (activeTransfers == nil) {
-        activeTransfers = [[NSMutableDictionary alloc] init];
+    if (self.queue == nil) {
+        self.queue = [[NSOperationQueue alloc] init];
+    }
+    [delegate.connection setDelegateQueue:self.queue];
+
+    @synchronized (activeTransfers) {
+        activeTransfers[delegate.objectId] = delegate;
     }
 
-    [activeTransfers setObject:delegate forKey:delegate.objectId];
+    [delegate.connection start];
 }
 
 - (NSMutableDictionary*)createFileTransferError:(int)code AndSource:(NSString*)source AndTarget:(NSString*)target
@@ -460,13 +474,13 @@
     return result;
 }
 
-- (void)onReset
-{
-    for (CDVFileTransferDelegate* delegate in [activeTransfers allValues]) {
-        [delegate.connection cancel];
+- (void)onReset {
+    @synchronized (activeTransfers) {
+        while ([activeTransfers count] > 0) {
+            CDVFileTransferDelegate* delegate = [activeTransfers allValues][0];
+            [delegate cancelTransfer:delegate.connection];
+        }
     }
-
-    [activeTransfers removeAllObjects];
 }
 
 @end
@@ -513,7 +527,7 @@
 
 @implementation CDVFileTransferDelegate
 
-@synthesize callbackId, connection = _connection, source, target, responseData, command, bytesTransfered, bytesExpected, direction, responseCode, objectId, targetFileHandle;
+@synthesize callbackId, connection = _connection, source, target, responseData, responseHeaders, command, bytesTransfered, bytesExpected, direction, responseCode, objectId, targetFileHandle, filePlugin;
 
 - (void)connectionDidFinishLoading:(NSURLConnection*)connection
 {
@@ -532,6 +546,7 @@
             uploadResult = [NSMutableDictionary dictionaryWithCapacity:3];
             if (uploadResponse != nil) {
                 [uploadResult setObject:uploadResponse forKey:@"response"];
+                [uploadResult setObject:self.responseHeaders forKey:@"headers"];
             }
             [uploadResult setObject:[NSNumber numberWithLongLong:self.bytesTransfered] forKey:@"bytesSent"];
             [uploadResult setObject:[NSNumber numberWithInt:self.responseCode] forKey:@"responseCode"];
@@ -546,7 +561,7 @@
             self.targetFileHandle = nil;
             DLog(@"File Transfer Download success");
 
-            result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:[filePlugin makeEntryForURL:self.targetURL]];
+            result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:[self.filePlugin makeEntryForURL:self.targetURL]];
         } else {
             downloadResponse = [[NSString alloc] initWithData:self.responseData encoding:NSUTF8StringEncoding];
             result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:[command createFileTransferError:CONNECTION_ERR AndSource:source AndTarget:target AndHttpStatus:self.responseCode AndBody:downloadResponse]];
@@ -556,11 +571,12 @@
     [self.command.commandDelegate sendPluginResult:result callbackId:callbackId];
 
     // remove connection for activeTransfers
-    [command.activeTransfers removeObjectForKey:objectId];
-
-    // remove background id task in case our upload was done in the background
-    [[UIApplication sharedApplication] endBackgroundTask:self.command.backgroundTaskID];
-    self.command.backgroundTaskID = UIBackgroundTaskInvalid;
+    @synchronized (command.activeTransfers) {
+        [command.activeTransfers removeObjectForKey:objectId];
+        // remove background id task in case our upload was done in the background
+        [[UIApplication sharedApplication] endBackgroundTask:self.backgroundTaskID];
+        self.backgroundTaskID = UIBackgroundTaskInvalid;
+    }
 }
 
 - (void)removeTargetFile
@@ -573,7 +589,13 @@
 - (void)cancelTransfer:(NSURLConnection*)connection
 {
     [connection cancel];
-    [self.command.activeTransfers removeObjectForKey:self.objectId];
+    @synchronized (self.command.activeTransfers) {
+        CDVFileTransferDelegate* delegate = self.command.activeTransfers[self.objectId];
+        [self.command.activeTransfers removeObjectForKey:self.objectId];
+        [[UIApplication sharedApplication] endBackgroundTask:delegate.backgroundTaskID];
+        delegate.backgroundTaskID = UIBackgroundTaskInvalid;
+    }
+
     [self removeTargetFile];
 }
 
@@ -600,6 +622,7 @@
 
         self.responseCode = [httpResponse statusCode];
         self.bytesExpected = [response expectedContentLength];
+        self.responseHeaders = [httpResponse allHeaderFields];
         if ((self.direction == CDV_TRANSFER_DOWNLOAD) && (self.responseCode == 200) && (self.bytesExpected == NSURLResponseUnknownLength)) {
             // Kick off HEAD request to server to get real length
             // bytesExpected will be updated when that response is returned
@@ -619,7 +642,7 @@
         CDVFilesystemURL *sourceURL = [CDVFilesystemURL fileSystemURLWithString:self.target];
         if (sourceURL && sourceURL.fileSystemName != nil) {
             // This requires talking to the current CDVFile plugin
-            NSObject<CDVFileSystem> *fs = [filePlugin filesystemForURL:sourceURL];
+            NSObject<CDVFileSystem> *fs = [self.filePlugin filesystemForURL:sourceURL];
             filePath = [fs filesystemPathForURL:sourceURL];
         } else {
             // Extract the path part out of a file: URL.
diff --git a/src/wp/FileTransfer.cs b/src/wp/FileTransfer.cs
index f9fe3fe..f8b6ed5 100644
--- a/src/wp/FileTransfer.cs
+++ b/src/wp/FileTransfer.cs
@@ -285,7 +285,7 @@
                     return;
                 }
                 webRequest = (HttpWebRequest)WebRequest.Create(serverUri);
-                webRequest.ContentType = "multipart/form-data;boundary=" + Boundary;
+                webRequest.ContentType = "multipart/form-data; boundary=" + Boundary;
                 webRequest.Method = uploadOptions.Method;
 
                 if (!string.IsNullOrEmpty(uploadOptions.Headers))
diff --git a/www/FileTransfer.js b/www/FileTransfer.js
index d6690fe..d842c5a 100644
--- a/www/FileTransfer.js
+++ b/www/FileTransfer.js
@@ -184,7 +184,8 @@
             entry.isFile = result.isFile;
             entry.name = result.name;
             entry.fullPath = result.fullPath;
-            entry.filesystem = new FileSystem(result.filesystem == window.PERSISTENT ? 'persistent' : 'temporary');
+            entry.filesystem = new FileSystem(result.filesystemName || (result.filesystem == window.PERSISTENT ? 'persistent' : 'temporary'));
+            entry.nativeURL = result.nativeURL;
             successCallback(entry);
         }
     };