aboutsummaryrefslogtreecommitdiffstats
path: root/perllib/FixMyStreet/Geocode.pm
blob: d552afaa547e8571f73e21a5a3d32c1b2913c3ac (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# FixMyStreet::Geocode
# The geocoding functions for FixMyStreet.
#
# Copyright (c) 2010 UK Citizens Online Democracy. All rights reserved.
# Email: matthew@mysociety.org; WWW: http://www.mysociety.org/

package FixMyStreet::Geocode;

use strict;
use Digest::MD5 qw(md5_hex);
use Encode;
use JSON::MaybeXS;
use LWP::Simple qw($ua);
use Path::Tiny;
use URI::Escape;
use FixMyStreet::Geocode::Bing;
use FixMyStreet::Geocode::Google;
use FixMyStreet::Geocode::OSM;
use FixMyStreet::Geocode::Zurich;
use Utils;

# lookup STRING CONTEXT
# Given a user-inputted string, try and convert it into co-ordinates using either
# MaPit if it's a postcode, or some web API otherwise. Returns an array of
# data, including an error if there is one. The information in the query may be
# used by cobranded versions of the site to diambiguate locations.
sub lookup {
    my ($s, $c) = @_;
    my $data = $c->cobrand->geocode_postcode($s);
    if (defined $data->{latitude}) {
        ( $data->{latitude}, $data->{longitude} ) =
            map { Utils::truncate_coordinate($_) }
            ( $data->{latitude}, $data->{longitude} );
    }
    $data = string($s, $c)
        unless $data->{error} || defined $data->{latitude};
    $data->{error} = _('Sorry, we could not find that location.')
        unless $data->{error} || defined $data->{latitude};
    return ( $data->{latitude}, $data->{longitude}, $data->{error} );
}

# string STRING CONTEXT
# Passes the string to some external API to look stuff up.
sub string {
    my ($s, $c) = @_;

    my $service = $c->cobrand->get_geocoder($c);
    $service = $service->{type} if ref $service;
    $service = 'OSM' unless $service =~ /^(Bing|Google|OSM|Zurich)$/;
    $service = 'OSM' if $service eq 'Bing' && !FixMyStreet->config('BING_MAPS_API_KEY');
    $service = "FixMyStreet::Geocode::${service}::string";

    no strict 'refs';
    return &$service($s, $c);
}

# escape STRING CONTEXT
# Escapes string for putting in URL geocoding call
sub escape {
    my ($s, $c) = @_;
    $s = lc($s);
    $s =~ s/[^-&\w ',]/ /g;
    $s =~ s/\s+/ /g;
    $s = URI::Escape::uri_escape_utf8($s);
    $s =~ s/%20/+/g;
    return $s;
}

sub cache {
    my ($type, $url, $args, $re) = @_;

    my $cache_dir = path(FixMyStreet->config('GEO_CACHE'), $type)->absolute(FixMyStreet->path_to());
    my $cache_file = $cache_dir->child(md5_hex($url));
    my $js;
    if (-s $cache_file && -M $cache_file <= 7 && !FixMyStreet->config('STAGING_SITE')) {
        # uncoverable statement
        $js = $cache_file->slurp_utf8;
    } else {
        $url .= '&' . $args if $args;
        $ua->timeout(15);
        $js = LWP::Simple::get($url);
        # The returned data is not correctly decoded if the content type is
        # e.g. application/json. Which all of our geocoders return.
        # uncoverable branch false
        $js = decode_utf8($js) if !utf8::is_utf8($js);
        if ($js && (!$re || $js !~ $re) && !FixMyStreet->config('STAGING_SITE')) {
            $cache_dir->mkpath; # uncoverable statement
            # uncoverable statement
            $cache_file->spew_utf8($js);
        }
    }
    $js = JSON->new->allow_nonref->decode($js) if $js;
    return $js;
}

1;
nd limitations under the License. */ #import "CDV.h" #import <AssetsLibrary/ALAsset.h> #import <AssetsLibrary/ALAssetRepresentation.h> #import <AssetsLibrary/ALAssetsLibrary.h> #import <CFNetwork/CFNetwork.h> @interface CDVFileTransfer () // Sets the requests headers for the request. - (void)applyRequestHeaders:(NSDictionary*)headers toRequest:(NSMutableURLRequest*)req; // Creates a delegate to handle an upload. - (CDVFileTransferDelegate*)delegateForUploadCommand:(CDVInvokedUrlCommand*)command; // Creates an NSData* for the file for the given upload arguments. - (void)fileDataForUploadCommand:(CDVInvokedUrlCommand*)command; @end // Buffer size to use for streaming uploads. static const NSUInteger kStreamBufferSize = 32768; // Magic value within the options dict used to set a cookie. NSString* const kOptionsKeyCookie = @"__cookie"; // Form boundary for multi-part requests. NSString* const kFormBoundary = @"+++++org.apache.cordova.formBoundary"; // Writes the given data to the stream in a blocking way. // If successful, returns bytesToWrite. // If the stream was closed on the other end, returns 0. // If there was an error, returns -1. static CFIndex WriteDataToStream(NSData* data, CFWriteStreamRef stream) { UInt8* bytes = (UInt8*)[data bytes]; NSUInteger bytesToWrite = [data length]; NSUInteger totalBytesWritten = 0; while (totalBytesWritten < bytesToWrite) { CFIndex result = CFWriteStreamWrite(stream, bytes + totalBytesWritten, bytesToWrite - totalBytesWritten); if (result < 0) { CFStreamError error = CFWriteStreamGetError(stream); NSLog(@"WriteStreamError domain: %ld error: %ld", error.domain, error.error); return result; } else if (result == 0) { return result; } totalBytesWritten += result; } return totalBytesWritten; } @implementation CDVFileTransfer @synthesize activeTransfers; - (NSString*)escapePathComponentForUrlString:(NSString*)urlString { NSRange schemeAndHostRange = [urlString rangeOfString:@"://.*?/" options:NSRegularExpressionSearch]; if (schemeAndHostRange.length == 0) { return urlString; } NSInteger schemeAndHostEndIndex = NSMaxRange(schemeAndHostRange); NSString* schemeAndHost = [urlString substringToIndex:schemeAndHostEndIndex]; NSString* pathComponent = [urlString substringFromIndex:schemeAndHostEndIndex]; pathComponent = [pathComponent stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; return [schemeAndHost stringByAppendingString:pathComponent]; } - (void)applyRequestHeaders:(NSDictionary*)headers toRequest:(NSMutableURLRequest*)req { [req setValue:@"XMLHttpRequest" forHTTPHeaderField:@"X-Requested-With"]; NSString* userAgent = [self.commandDelegate userAgent]; if (userAgent) { [req setValue:userAgent forHTTPHeaderField:@"User-Agent"]; } for (NSString* headerName in headers) { id value = [headers objectForKey:headerName]; if (!value || (value == [NSNull null])) { value = @"null"; } // First, remove an existing header if one exists. [req setValue:nil forHTTPHeaderField:headerName]; if (![value isKindOfClass:[NSArray class]]) { value = [NSArray arrayWithObject:value]; } // Then, append all header values. for (id __strong subValue in value) { // Convert from an NSNumber -> NSString. if ([subValue respondsToSelector:@selector(stringValue)]) { subValue = [subValue stringValue]; } if ([subValue isKindOfClass:[NSString class]]) { [req addValue:subValue forHTTPHeaderField:headerName]; } } } } - (NSURLRequest*)requestForUploadCommand:(CDVInvokedUrlCommand*)command fileData:(NSData*)fileData { // arguments order from js: [filePath, server, fileKey, fileName, mimeType, params, debug, chunkedMode] // however, params is a JavaScript object and during marshalling is put into the options dict, // thus debug and chunkedMode are the 6th and 7th arguments NSArray* arguments = command.arguments; NSString* target = (NSString*)[arguments objectAtIndex:0]; NSString* server = (NSString*)[arguments objectAtIndex:1]; NSString* fileKey = [arguments objectAtIndex:2 withDefault:@"file"]; NSString* fileName = [arguments objectAtIndex:3 withDefault:@"no-filename"]; NSString* mimeType = [arguments objectAtIndex:4 withDefault:nil]; NSDictionary* options = [arguments objectAtIndex:5 withDefault:nil]; // BOOL trustAllHosts = [[arguments objectAtIndex:6 withDefault:[NSNumber numberWithBool:YES]] boolValue]; // allow self-signed certs BOOL chunkedMode = [[arguments objectAtIndex:7 withDefault:[NSNumber numberWithBool:YES]] boolValue]; NSDictionary* headers = [arguments objectAtIndex:8 withDefault:nil]; CDVPluginResult* result = nil; CDVFileTransferError errorCode = 0; // NSURL does not accepts URLs with spaces in the path. We escape the path in order // to be more lenient. NSURL* url = [NSURL URLWithString:server]; if (!url) { errorCode = INVALID_URL_ERR; NSLog(@"File Transfer Error: Invalid server URL %@", server); } else if (!fileData) { errorCode = FILE_NOT_FOUND_ERR; } if (errorCode > 0) { result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:[self createFileTransferError:errorCode AndSource:target AndTarget:server]]; [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; return nil; } NSMutableURLRequest* req = [NSMutableURLRequest requestWithURL:url]; [req setHTTPMethod:@"POST"]; // Magic value to set a cookie if ([options objectForKey:kOptionsKeyCookie]) { [req setValue:[options objectForKey:kOptionsKeyCookie] forHTTPHeaderField:@"Cookie"]; [req setHTTPShouldHandleCookies:NO]; } NSString* contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", kFormBoundary]; [req setValue:contentType forHTTPHeaderField:@"Content-Type"]; [self applyRequestHeaders:headers toRequest:req]; NSData* formBoundaryData = [[NSString stringWithFormat:@"--%@\r\n", kFormBoundary] dataUsingEncoding:NSUTF8StringEncoding]; NSMutableData* postBodyBeforeFile = [NSMutableData data]; for (NSString* key in options) { id val = [options objectForKey:key]; if (!val || (val == [NSNull null]) || [key isEqualToString:kOptionsKeyCookie]) { continue; } // if it responds to stringValue selector (eg NSNumber) get the NSString if ([val respondsToSelector:@selector(stringValue)]) { val = [val stringValue]; } // finally, check whether it is a NSString (for dataUsingEncoding selector below) if (![val isKindOfClass:[NSString class]]) { continue; } [postBodyBeforeFile appendData:formBoundaryData]; [postBodyBeforeFile appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n", key] dataUsingEncoding:NSUTF8StringEncoding]]; [postBodyBeforeFile appendData:[val dataUsingEncoding:NSUTF8StringEncoding]]; [postBodyBeforeFile appendData:[@"\r\n" dataUsingEncoding:NSUTF8StringEncoding]]; } [postBodyBeforeFile appendData:formBoundaryData]; [postBodyBeforeFile appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n", fileKey, fileName] dataUsingEncoding:NSUTF8StringEncoding]]; if (mimeType != nil) { [postBodyBeforeFile appendData:[[NSString stringWithFormat:@"Content-Type: %@\r\n", mimeType] dataUsingEncoding:NSUTF8StringEncoding]]; } [postBodyBeforeFile appendData:[[NSString stringWithFormat:@"Content-Length: %d\r\n\r\n", [fileData length]] dataUsingEncoding:NSUTF8StringEncoding]]; DLog(@"fileData length: %d", [fileData length]); NSData* postBodyAfterFile = [[NSString stringWithFormat:@"\r\n--%@--\r\n", kFormBoundary] dataUsingEncoding:NSUTF8StringEncoding]; NSUInteger totalPayloadLength = [postBodyBeforeFile length] + [fileData length] + [postBodyAfterFile length]; [req setValue:[[NSNumber numberWithInteger:totalPayloadLength] stringValue] forHTTPHeaderField:@"Content-Length"]; if (chunkedMode) { CFReadStreamRef readStream = NULL; CFWriteStreamRef writeStream = NULL; CFStreamCreateBoundPair(NULL, &readStream, &writeStream, kStreamBufferSize); [req setHTTPBodyStream:CFBridgingRelease(readStream)]; [self.commandDelegate runInBackground:^{ if (CFWriteStreamOpen (writeStream)) { NSData* chunks[] = {postBodyBeforeFile, fileData, postBodyAfterFile}; int numChunks = sizeof (chunks) / sizeof (chunks[0]); for (int i = 0; i < numChunks; ++i) { CFIndex result = WriteDataToStream (chunks[i], writeStream); if (result <= 0) { break; } } } else { NSLog (@"FileTransfer: Failed to open writeStream"); } CFWriteStreamClose (writeStream); CFRelease (writeStream); }]; } else { [postBodyBeforeFile appendData:fileData]; [postBodyBeforeFile appendData:postBodyAfterFile]; [req setHTTPBody:postBodyBeforeFile]; } return req; } - (CDVFileTransferDelegate*)delegateForUploadCommand:(CDVInvokedUrlCommand*)command { 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 NSString* objectId = [command.arguments objectAtIndex:9]; CDVFileTransferDelegate* delegate = [[CDVFileTransferDelegate alloc] init]; delegate.command = self; delegate.callbackId = command.callbackId; delegate.direction = CDV_TRANSFER_UPLOAD; delegate.objectId = objectId; delegate.source = source; delegate.target = server; delegate.trustAllHosts = trustAllHosts; return delegate; } - (void)fileDataForUploadCommand:(CDVInvokedUrlCommand*)command { NSString* target = (NSString*)[command.arguments objectAtIndex:0]; NSError* __autoreleasing err = nil; // return unsupported result for assets-library URLs if ([target hasPrefix:kCDVAssetsLibraryPrefix]) { // Instead, we return after calling the asynchronous method and send `result` in each of the blocks. ALAssetsLibraryAssetForURLResultBlock resultBlock = ^(ALAsset * asset) { if (asset) { // We have the asset! Get the data and send it off. ALAssetRepresentation* assetRepresentation = [asset defaultRepresentation]; Byte* buffer = (Byte*)malloc ([assetRepresentation size]); NSUInteger bufferSize = [assetRepresentation getBytes:buffer fromOffset:0.0 length:[assetRepresentation size] error:nil]; NSData* fileData = [NSData dataWithBytesNoCopy:buffer length:bufferSize freeWhenDone:YES]; [self uploadData:fileData command:command]; } else { // We couldn't find the asset. Send the appropriate error. CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsInt:NOT_FOUND_ERR]; [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; } }; ALAssetsLibraryAccessFailureBlock failureBlock = ^(NSError * error) { // Retrieving the asset failed for some reason. Send the appropriate error. CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsString:[error localizedDescription]]; [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; }; ALAssetsLibrary* assetsLibrary = [[ALAssetsLibrary alloc] init]; [assetsLibrary assetForURL:[NSURL URLWithString:target] resultBlock:resultBlock failureBlock:failureBlock]; return; } else { // Extract the path part out of a file: URL. NSString* filePath = [target hasPrefix:@"/"] ? [target copy] : [[NSURL URLWithString:target] path]; // Memory map the file so that it can be read efficiently even if it is large. NSData* fileData = [NSData dataWithContentsOfFile:filePath options:NSDataReadingMappedIfSafe error:&err]; if (err != nil) { NSLog (@"Error opening file %@: %@", target, err); } [self uploadData:fileData command:command]; } } - (void)upload:(CDVInvokedUrlCommand*)command { // fileData and req are split into helper functions to ease the unit testing of delegateForUpload. // First, get the file data. This method will call `uploadData:command`. [self fileDataForUploadCommand:command]; } - (void)uploadData:(NSData*)fileData command:(CDVInvokedUrlCommand*)command { NSURLRequest* req = [self requestForUploadCommand:command fileData:fileData]; if (req == nil) { return; } CDVFileTransferDelegate* delegate = [self delegateForUploadCommand:command]; [NSURLConnection connectionWithRequest:req delegate:delegate]; if (activeTransfers == nil) { activeTransfers = [[NSMutableDictionary alloc] init]; } [activeTransfers setObject:delegate forKey:delegate.objectId]; } - (void)abort:(CDVInvokedUrlCommand*)command { NSString* objectId = [command.arguments objectAtIndex:0]; CDVFileTransferDelegate* delegate = [activeTransfers objectForKey:objectId]; if (delegate != nil) { [delegate.connection cancel]; [activeTransfers removeObjectForKey:objectId]; // delete uncomplete file NSFileManager* fileMgr = [NSFileManager defaultManager]; [fileMgr removeItemAtPath:delegate.target error:nil]; CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:[self createFileTransferError:CONNECTION_ABORTED AndSource:delegate.source AndTarget:delegate.target]]; [self.commandDelegate sendPluginResult:result callbackId:delegate.callbackId]; } } - (void)download:(CDVInvokedUrlCommand*)command { DLog(@"File Transfer downloading file..."); NSString* sourceUrl = [command.arguments objectAtIndex:0]; NSString* filePath = [command.arguments objectAtIndex:1]; BOOL trustAllHosts = [[command.arguments objectAtIndex:2 withDefault:[NSNumber numberWithBool:YES]] boolValue]; // allow self-signed certs NSString* objectId = [command.arguments objectAtIndex:3]; // return unsupported result for assets-library URLs if ([filePath hasPrefix:kCDVAssetsLibraryPrefix]) { CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_MALFORMED_URL_EXCEPTION messageAsString:@"download not supported for assets-library URLs."]; [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; return; } CDVPluginResult* result = nil; CDVFileTransferError errorCode = 0; NSURL* file; if ([filePath hasPrefix:@"/"]) { file = [NSURL fileURLWithPath:filePath]; } else { file = [NSURL URLWithString:filePath]; } NSURL* url = [NSURL URLWithString:sourceUrl]; if (!url) { errorCode = INVALID_URL_ERR; NSLog(@"File Transfer Error: Invalid server URL %@", sourceUrl); } else if (![file isFileURL]) { errorCode = FILE_NOT_FOUND_ERR; NSLog(@"File Transfer Error: Invalid file path or URL %@", filePath); } if (errorCode > 0) { result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:[self createFileTransferError:errorCode AndSource:sourceUrl AndTarget:filePath]]; [self.commandDelegate sendPluginResult:result callbackId:command.callbackId]; return; } NSMutableURLRequest* req = [NSMutableURLRequest requestWithURL:url]; [self applyRequestHeaders:nil toRequest:req]; CDVFileTransferDelegate* delegate = [[CDVFileTransferDelegate alloc] init]; delegate.command = self; delegate.direction = CDV_TRANSFER_DOWNLOAD; delegate.callbackId = command.callbackId; delegate.objectId = objectId; delegate.source = sourceUrl; delegate.target = filePath; delegate.trustAllHosts = trustAllHosts; delegate.connection = [NSURLConnection connectionWithRequest:req delegate:delegate]; if (activeTransfers == nil) { activeTransfers = [[NSMutableDictionary alloc] init]; } [activeTransfers setObject:delegate forKey:delegate.objectId]; } - (NSMutableDictionary*)createFileTransferError:(int)code AndSource:(NSString*)source AndTarget:(NSString*)target { NSMutableDictionary* result = [NSMutableDictionary dictionaryWithCapacity:3]; [result setObject:[NSNumber numberWithInt:code] forKey:@"code"]; [result setObject:source forKey:@"source"]; [result setObject:target forKey:@"target"]; NSLog(@"FileTransferError %@", result); return result; } - (NSMutableDictionary*)createFileTransferError:(int)code AndSource:(NSString*)source AndTarget:(NSString*)target AndHttpStatus:(int)httpStatus AndBody:(NSString*)body { NSMutableDictionary* result = [NSMutableDictionary dictionaryWithCapacity:5]; [result setObject:[NSNumber numberWithInt:code] forKey:@"code"]; [result setObject:source forKey:@"source"]; [result setObject:target forKey:@"target"]; [result setObject:[NSNumber numberWithInt:httpStatus] forKey:@"http_status"]; [result setObject:body forKey:@"body"]; NSLog(@"FileTransferError %@", result); return result; } - (void)onReset { for (CDVFileTransferDelegate* delegate in [activeTransfers allValues]) { [delegate.connection cancel]; } [activeTransfers removeAllObjects]; } @end @implementation CDVFileTransferDelegate @synthesize callbackId, connection, source, target, responseData, command, bytesTransfered, bytesExpected, direction, responseCode, objectId; - (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; NSLog(@"File Transfer Finished with response code %d", self.responseCode); if (self.direction == CDV_TRANSFER_UPLOAD) { uploadResponse = [[NSString alloc] initWithData:self.responseData encoding:NSUTF8StringEncoding]; if ((self.responseCode >= 200) && (self.responseCode < 300)) { // create dictionary to return FileUploadResult object uploadResult = [NSMutableDictionary dictionaryWithCapacity:3]; if (uploadResponse != nil) { [uploadResult setObject:uploadResponse forKey:@"response"]; } [uploadResult setObject:[NSNumber numberWithInt:self.bytesTransfered] forKey:@"bytesSent"]; [uploadResult setObject:[NSNumber numberWithInt:self.responseCode] forKey:@"responseCode"]; result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:uploadResult]; } else { result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:[command createFileTransferError:CONNECTION_ERR AndSource:source AndTarget:target AndHttpStatus:self.responseCode AndBody:uploadResponse]]; } } 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]; 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]]; } } 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]]; } } [self.command.commandDelegate sendPluginResult:result callbackId:callbackId]; // remove connection for activeTransfers [command.activeTransfers removeObjectForKey:objectId]; } - (void)connection:(NSURLConnection*)connection didReceiveResponse:(NSURLResponse*)response { self.mimeType = [response MIMEType]; // required for iOS 4.3, for some reason; response is // a plain NSURLResponse, not the HTTP subclass if ([response isKindOfClass:[NSHTTPURLResponse class]]) { NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response; self.responseCode = [httpResponse statusCode]; self.bytesExpected = [response expectedContentLength]; } else if ([response.URL isFileURL]) { NSDictionary* attr = [[NSFileManager defaultManager] attributesOfItemAtPath:[response.URL path] error:nil]; self.responseCode = 200; self.bytesExpected = [attr[NSFileSize] longLongValue]; } else { self.responseCode = 200; self.bytesExpected = NSURLResponseUnknownLength; } } - (void)connection:(NSURLConnection*)connection didFailWithError:(NSError*)error { NSString* body = [[NSString alloc] initWithData:self.responseData encoding:NSUTF8StringEncoding]; CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:[command createFileTransferError:CONNECTION_ERR AndSource:source AndTarget:target AndHttpStatus:self.responseCode AndBody:body]]; NSLog(@"File Transfer Error: %@", [error localizedDescription]); // remove connection for activeTransfers [command.activeTransfers removeObjectForKey:objectId]; [self.command.commandDelegate sendPluginResult:result callbackId:callbackId]; } - (void)connection:(NSURLConnection*)connection didReceiveData:(NSData*)data { self.bytesTransfered += data.length; [self.responseData appendData:data]; if (self.direction == CDV_TRANSFER_DOWNLOAD) { BOOL lengthComputable = (self.bytesExpected != NSURLResponseUnknownLength); NSMutableDictionary* downloadProgress = [NSMutableDictionary dictionaryWithCapacity:3]; [downloadProgress setObject:[NSNumber numberWithBool:lengthComputable] forKey:@"lengthComputable"]; [downloadProgress setObject:[NSNumber numberWithInt:self.bytesTransfered] forKey:@"loaded"]; [downloadProgress setObject:[NSNumber numberWithInt:self.bytesExpected] forKey:@"total"]; CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:downloadProgress]; [result setKeepCallbackAsBool:true]; [self.command.commandDelegate sendPluginResult:result callbackId:callbackId]; } } - (void)connection:(NSURLConnection*)connection didSendBodyData:(NSInteger)bytesWritten totalBytesWritten:(NSInteger)totalBytesWritten totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite { if (self.direction == CDV_TRANSFER_UPLOAD) { NSMutableDictionary* uploadProgress = [NSMutableDictionary dictionaryWithCapacity:3]; [uploadProgress setObject:[NSNumber numberWithBool:true] forKey:@"lengthComputable"]; [uploadProgress setObject:[NSNumber numberWithInt:totalBytesWritten] forKey:@"loaded"]; [uploadProgress setObject:[NSNumber numberWithInt:totalBytesExpectedToWrite] forKey:@"total"]; CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsDictionary:uploadProgress]; [result setKeepCallbackAsBool:true]; [self.command.commandDelegate sendPluginResult:result callbackId:callbackId]; } self.bytesTransfered = totalBytesWritten; } // for self signed certificates - (void)connection:(NSURLConnection*)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge*)challenge { if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { if (self.trustAllHosts) { NSURLCredential* credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]; [challenge.sender useCredential:credential forAuthenticationChallenge:challenge]; } [challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge]; } else { [challenge.sender performDefaultHandlingForAuthenticationChallenge:challenge]; } } - (id)init { if ((self = [super init])) { self.responseData = [NSMutableData data]; } return self; } @end;