Allow uploading a native file (e.g. photo) via XMLHttpRequest

Summary:
With this in place, it's possible to upload a picture from the `CameraRoll` to Parse, for instance:

    xhr = new XMLHttpRequest();
    xhr.onload = function() {
      data = JSON.parse(xhr.responseText);
      var parseFile = new Parse.File(data.name);
      parseFile._url = data.url;
      callback(parseFile);
    };
    xhr.setRequestHeader('X-Parse-Application-Id', appID);
    xhr.setRequestHeader('X-Parse-JavaScript-Key', appKey);
    xhr.open('POST', 'https://api.parse.com/1/files/image.jpg');
    // assetURI as provided e.g. by the CameraRoll API
    xhr.send(new NativeFile(assetURI));

Closes https://github.com/facebook/react-native/pull/1357
Github Author: Philipp von Weitershausen <philikon@fb.com>

Test Plan: Imported from GitHub, without a `Test Plan:` line.
This commit is contained in:
Philipp von Weitershausen 2015-05-26 10:28:33 -07:00
parent 7069e4cd3f
commit 4273af9e29
5 changed files with 55 additions and 10 deletions

View File

@ -23,4 +23,6 @@
+ (void)loadImageWithTag:(NSString *)tag
callback:(void (^)(NSError *error, id /* UIImage or CAAnimation */ image))callback;
+ (BOOL)isSystemImageURI:(NSString *)uri;
@end

View File

@ -154,4 +154,11 @@ static void RCTDispatchCallbackOnMainQueue(void (^callback)(NSError *, id), NSEr
}
}
+ (BOOL)isSystemImageURI:(NSString *)uri
{
return uri != nil && (
[uri hasPrefix:@"assets-library"] ||
[uri hasPrefix:@"ph://"]);
}
@end

View File

@ -13,6 +13,7 @@
#import "RCTConvert.h"
#import "RCTLog.h"
#import "RCTUtils.h"
#import "RCTImageLoader.h"
@implementation RCTDataManager
@ -34,8 +35,43 @@ RCT_EXPORT_METHOD(queryData:(NSString *)queryType
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];
request.HTTPMethod = [RCTConvert NSString:query[@"method"]] ?: @"GET";
request.allHTTPHeaderFields = [RCTConvert NSDictionary:query[@"headers"]];
request.HTTPBody = [RCTConvert NSData:query[@"data"]];
if (query[@"data"] != [NSNull null]) {
NSDictionary *data = [RCTConvert NSDictionary:query[@"data"]];
NSData *body = [RCTConvert NSData:data[@"string"]];
if (body != nil) {
request.HTTPBody = body;
[RCTDataManager sendRequest:request responseSender:responseSender];
return;
}
NSString *uri = [RCTConvert NSString:data[@"uri"]];
if (uri != nil) {
if ([RCTImageLoader isSystemImageURI:uri]) {
[RCTImageLoader loadImageWithTag:(NSString *)uri callback:^(NSError *error, UIImage *image) {
if (error) {
RCTLogError(@"Error loading image URI: %@", error);
// We should really circle back to JS here and notify an error/abort on the request.
return;
}
NSData *imageData = UIImageJPEGRepresentation(image, 1.0);
request.HTTPBody = imageData;
[RCTDataManager sendRequest:request responseSender:responseSender];
}];
} else {
RCTLogError(@"Cannot resolve URI: %@", uri);
}
return;
}
}
// There was no data payload, or we couldn't understand it.
[RCTDataManager sendRequest:request responseSender:responseSender];
} else {
RCTLogError(@"unsupported query type %@", queryType);
}
}
+ (void)sendRequest:(NSURLRequest *)request responseSender:(RCTResponseSenderBlock)responseSender {
// Build data task
NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *connectionError) {
@ -71,11 +107,6 @@ RCT_EXPORT_METHOD(queryData:(NSString *)queryType
}];
[task resume];
} else {
RCTLogError(@"unsupported query type %@", queryType);
}
}
@end

View File

@ -209,6 +209,7 @@
"$(inherited)",
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
"$(SRCROOT)/../../React/**",
"$(SRCROOT)/../Image/**",
);
LIBRARY_SEARCH_PATHS = "$(inherited)";
OTHER_LDFLAGS = "-ObjC";
@ -226,6 +227,7 @@
"$(inherited)",
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
"$(SRCROOT)/../../React/**",
"$(SRCROOT)/../Image/**",
);
LIBRARY_SEARCH_PATHS = "$(inherited)";
OTHER_LDFLAGS = "-ObjC";

View File

@ -20,13 +20,16 @@ var XMLHttpRequestBase = require('XMLHttpRequestBase');
class XMLHttpRequest extends XMLHttpRequestBase {
sendImpl(method: ?string, url: ?string, headers: Object, data: any): void {
if (typeof data === 'string') {
data = {string: data};
}
RCTDataManager.queryData(
'http',
{
method: method,
url: url,
data: data,
headers: headers,
method,
url,
data,
headers,
},
// TODO: Do we need this? is it used anywhere?
'h' + crc32(method + '|' + url + '|' + data),