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 19:04:22 UTC

ios commit: [CB-2537] Implement streaming downloads for FileTransfer

Updated Branches:
  refs/heads/master 3e007c35f -> d6a35768e


[CB-2537] Implement streaming downloads for FileTransfer


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

Branch: refs/heads/master
Commit: d6a35768e74bda0e77a1bbe0aba8fcfe41c7b5c0
Parents: 3e007c3
Author: Ian Clelland <ic...@chromium.org>
Authored: Thu Mar 21 11:49:57 2013 -0400
Committer: Andrew Grieve <ag...@chromium.org>
Committed: Wed Mar 27 14:04:00 2013 -0400

----------------------------------------------------------------------
 CordovaLib/Classes/CDVFileTransfer.h |    1 +
 CordovaLib/Classes/CDVFileTransfer.m |   87 +++++++++++++++++------------
 2 files changed, 52 insertions(+), 36 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/d6a35768/CordovaLib/Classes/CDVFileTransfer.h
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVFileTransfer.h b/CordovaLib/Classes/CDVFileTransfer.h
index d82cdd3..404220b 100644
--- a/CordovaLib/Classes/CDVFileTransfer.h
+++ b/CordovaLib/Classes/CDVFileTransfer.h
@@ -70,5 +70,6 @@ extern NSString* const kOptionsKeyCookie;
 @property (nonatomic, assign) NSInteger bytesTransfered;
 @property (nonatomic, assign) NSInteger bytesExpected;
 @property (nonatomic, assign) BOOL trustAllHosts;
+@property (strong) NSFileHandle* targetFileHandle;
 
 @end;

http://git-wip-us.apache.org/repos/asf/cordova-ios/blob/d6a35768/CordovaLib/Classes/CDVFileTransfer.m
----------------------------------------------------------------------
diff --git a/CordovaLib/Classes/CDVFileTransfer.m b/CordovaLib/Classes/CDVFileTransfer.m
index 5741aca..9f14ef5 100644
--- a/CordovaLib/Classes/CDVFileTransfer.m
+++ b/CordovaLib/Classes/CDVFileTransfer.m
@@ -458,17 +458,14 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
 
 @implementation CDVFileTransferDelegate
 
-@synthesize callbackId, connection, source, target, responseData, command, bytesTransfered, bytesExpected, direction, responseCode, objectId;
+@synthesize callbackId, connection = _connection, source, target, responseData, command, bytesTransfered, bytesExpected, direction, responseCode, objectId, targetFileHandle;
 
 - (void)connectionDidFinishLoading:(NSURLConnection*)connection
 {
     NSString* uploadResponse = nil;
     NSString* downloadResponse = nil;
-    BOOL downloadWriteOK = NO;
     NSMutableDictionary* uploadResult;
     CDVPluginResult* result = nil;
-    NSError* __autoreleasing error = nil;
-    NSString* parentPath;
     BOOL bDirRequest = NO;
     CDVFile* file;
 
@@ -491,40 +488,15 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
         }
     }
     if (self.direction == CDV_TRANSFER_DOWNLOAD) {
-        DLog(@"Write file %@", target);
-        // error=[[NSError alloc]init];
-
-        if ((self.responseCode >= 200) && (self.responseCode < 300)) {
-            @try {
-                parentPath = [self.target stringByDeletingLastPathComponent];
-
-                // check if the path exists => create directories if needed
-                if (![[NSFileManager defaultManager] fileExistsAtPath:parentPath]) {
-                    [[NSFileManager defaultManager] createDirectoryAtPath:parentPath withIntermediateDirectories:YES attributes:nil error:nil];
-                }
-
-                downloadWriteOK = [self.responseData writeToFile:self.target options:NSDataWritingFileProtectionNone error:&error];
-
-                if (downloadWriteOK == NO) {
-                    // send our results back
-                    downloadResponse = [[NSString alloc] initWithData:self.responseData encoding:NSUTF8StringEncoding];
-                    result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:[command createFileTransferError:INVALID_URL_ERR AndSource:source AndTarget:target AndHttpStatus:self.responseCode AndBody:downloadResponse]];
-                } else {
-                    DLog(@"File Transfer Download success");
-
-                    file = [[CDVFile alloc] init];
+        if (self.targetFileHandle) {
+            [self.targetFileHandle closeFile];
+            self.targetFileHandle = nil;
+            DLog(@"File Transfer Download success");
 
-                    result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:[file getDirectoryEntry:target isDirectory:bDirRequest]];
-                }
-            }
-            @catch(id exception) {
-                // jump back to main thread
-                downloadResponse = [[NSString alloc] initWithData:self.responseData encoding:NSUTF8StringEncoding];
-                result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsDictionary:[command createFileTransferError:FILE_NOT_FOUND_ERR AndSource:source AndTarget:target AndHttpStatus:self.responseCode AndBody:downloadResponse]];
-            }
+            file = [[CDVFile alloc] init];
+            result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:[file getDirectoryEntry:target isDirectory:bDirRequest]];
         } 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]];
         }
     }
@@ -535,9 +507,22 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
     [command.activeTransfers removeObjectForKey:objectId];
 }
 
+- (void)cancelTransferWithError:(NSURLConnection*)connection errorMessage:(NSString*)errorMessage
+{
+    CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsDictionary:[self.command createFileTransferError:FILE_NOT_FOUND_ERR AndSource:self.source AndTarget:self.target AndHttpStatus:self.responseCode AndBody:errorMessage]];
+
+    NSLog(@"File Transfer Error: %@", errorMessage);
+    [connection cancel];
+    [self.command.activeTransfers removeObjectForKey:self.objectId];
+    [self.command.commandDelegate sendPluginResult:result callbackId:callbackId];
+}
+
 - (void)connection:(NSURLConnection*)connection didReceiveResponse:(NSURLResponse*)response
 {
+    NSError* __autoreleasing error = nil;
+
     self.mimeType = [response MIMEType];
+    self.targetFileHandle = nil;
 
     // required for iOS 4.3, for some reason; response is
     // a plain NSURLResponse, not the HTTP subclass
@@ -554,6 +539,31 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
         self.responseCode = 200;
         self.bytesExpected = NSURLResponseUnknownLength;
     }
+    if ((self.direction == CDV_TRANSFER_DOWNLOAD) && (self.responseCode >= 200) && (self.responseCode < 300)) {
+        // Download response is okay; begin streaming output to file
+        NSString* parentPath = [self.target stringByDeletingLastPathComponent];
+
+        // create parent directories if needed
+        if ([[NSFileManager defaultManager] createDirectoryAtPath:parentPath withIntermediateDirectories:YES attributes:nil error:&error] == NO) {
+            if (error) {
+                [self cancelTransferWithError:connection errorMessage:[NSString stringWithFormat:@"Could not create path to save downloaded file: %@", [error localizedDescription]]];
+            } else {
+                [self cancelTransferWithError:connection errorMessage:@"Could not create path to save downloaded file"];
+            }
+            return;
+        }
+        // create target file
+        if ([[NSFileManager defaultManager] createFileAtPath:self.target contents:nil attributes:nil] == NO) {
+            [self cancelTransferWithError:connection errorMessage:@"Could not create target file"];
+            return;
+        }
+        // open target file for writing
+        self.targetFileHandle = [NSFileHandle fileHandleForWritingAtPath:self.target];
+        if (self.targetFileHandle == nil) {
+            [self cancelTransferWithError:connection errorMessage:@"Could not open target file for writing"];
+        }
+        DLog(@"Streaming to file %@", target);
+    }
 }
 
 - (void)connection:(NSURLConnection*)connection didFailWithError:(NSError*)error
@@ -571,7 +581,11 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
 - (void)connection:(NSURLConnection*)connection didReceiveData:(NSData*)data
 {
     self.bytesTransfered += data.length;
-    [self.responseData appendData:data];
+    if (self.targetFileHandle) {
+        [self.targetFileHandle writeData:data];
+    } else {
+        [self.responseData appendData:data];
+    }
 
     if (self.direction == CDV_TRANSFER_DOWNLOAD) {
         BOOL lengthComputable = (self.bytesExpected != NSURLResponseUnknownLength);
@@ -618,6 +632,7 @@ static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream)
 {
     if ((self = [super init])) {
         self.responseData = [NSMutableData data];
+        self.targetFileHandle = nil;
     }
     return self;
 }