Skip to content

Commit b5027a0

Browse files
satya164facebook-github-bot
authored andcommitted
Implement Blob support for XMLHttpRequest
Summary: This PR is a followup to facebook/react-native#11417 and should be merged after that one is merged. 1. Add support for creating blobs from strings, not just other blobs 1. Add the `File` constructor which is a superset of `Blob` 1. Add the `FileReader` API which can be used to read blobs as strings or data url (base64) 1. Add support for uploading and downloading blobs via `XMLHttpRequest` and `fetch` 1. Add ability to download local files on Android so you can do `fetch(uri).then(res => res.blob())` to get a blob for a local file (iOS already supported this) 1. Clone the repo https://github.com/expo/react-native-blob-test 1. Change the `package.json` and update `react-native` dependency to point to this branch, then run `npm install` 1. Run the `server.js` file with `node server.js` 1. Open the `index.common.js` file and replace `localhost` with your computer's IP address 1. Start the packager with `yarn start` and run the app on your device If everything went well, all tests should pass, and you should see a screen like this: ![screen shot 2017-06-08 at 7 53 08 pm](https://user-images.githubusercontent.com/1174278/26936407-435bbce2-4c8c-11e7-9ae3-eb104e46961e.png)! Pull to rerun all tests or tap on specific test to re-run it [GENERAL] [FEATURE] [Blob] - Implement blob support for XMLHttpRequest Closes facebook/react-native#11573 Reviewed By: shergin Differential Revision: D6082054 Pulled By: hramos fbshipit-source-id: cc9c174fdefdfaf6e5d9fd7b300120a01a50e8c1
1 parent c4f1c18 commit b5027a0

File tree

3 files changed

+186
-0
lines changed

3 files changed

+186
-0
lines changed

RNTester.xcodeproj/project.pbxproj

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@
5353
192F69B91E82409A008692C7 /* RCTConvert_YGValueTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 192F69B61E82409A008692C7 /* RCTConvert_YGValueTests.m */; };
5454
192F69BA1E82409A008692C7 /* RCTNativeAnimatedNodesManagerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 192F69B71E82409A008692C7 /* RCTNativeAnimatedNodesManagerTests.m */; };
5555
192F69DA1E8240E2008692C7 /* libRCTAnimation.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 13E501A31D07A502005F35D8 /* libRCTAnimation.a */; };
56+
19BA88D51F84344F00741C5A /* RCTBlobManagerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 19BA88D41F84344F00741C5A /* RCTBlobManagerTests.m */; };
57+
19BA89031F8439A700741C5A /* libRCTBlob.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 5281CA511EEAC9A700AC40CD /* libRCTBlob.a */; };
5658
272E6B3F1BEA849E001FCF37 /* UpdatePropertiesExampleView.m in Sources */ = {isa = PBXBuildFile; fileRef = 272E6B3C1BEA849E001FCF37 /* UpdatePropertiesExampleView.m */; };
5759
27B885561BED29AF00008352 /* RCTRootViewIntegrationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 27B885551BED29AF00008352 /* RCTRootViewIntegrationTests.m */; };
5860
27F441EC1BEBE5030039B79C /* FlexibleSizeExampleView.m in Sources */ = {isa = PBXBuildFile; fileRef = 27F441E81BEBE5030039B79C /* FlexibleSizeExampleView.m */; };
@@ -515,6 +517,7 @@
515517
192F69B51E82409A008692C7 /* RCTAnimationUtilsTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTAnimationUtilsTests.m; sourceTree = "<group>"; };
516518
192F69B61E82409A008692C7 /* RCTConvert_YGValueTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTConvert_YGValueTests.m; sourceTree = "<group>"; };
517519
192F69B71E82409A008692C7 /* RCTNativeAnimatedNodesManagerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTNativeAnimatedNodesManagerTests.m; sourceTree = "<group>"; };
520+
19BA88D41F84344F00741C5A /* RCTBlobManagerTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RCTBlobManagerTests.m; sourceTree = "<group>"; };
518521
272E6B3B1BEA849E001FCF37 /* UpdatePropertiesExampleView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = UpdatePropertiesExampleView.h; path = RNTester/NativeExampleViews/UpdatePropertiesExampleView.h; sourceTree = "<group>"; };
519522
272E6B3C1BEA849E001FCF37 /* UpdatePropertiesExampleView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = UpdatePropertiesExampleView.m; path = RNTester/NativeExampleViews/UpdatePropertiesExampleView.m; sourceTree = "<group>"; };
520523
27B885551BED29AF00008352 /* RCTRootViewIntegrationTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTRootViewIntegrationTests.m; sourceTree = "<group>"; };
@@ -553,6 +556,7 @@
553556
isa = PBXFrameworksBuildPhase;
554557
buildActionMask = 2147483647;
555558
files = (
559+
19BA89031F8439A700741C5A /* libRCTBlob.a in Frameworks */,
556560
192F69DA1E8240E2008692C7 /* libRCTAnimation.a in Frameworks */,
557561
14D6D71E1B2222EF001FB087 /* libRCTActionSheet.a in Frameworks */,
558562
14D6D7201B2222EF001FB087 /* libRCTGeolocation.a in Frameworks */,
@@ -767,6 +771,7 @@
767771
isa = PBXGroup;
768772
children = (
769773
192F69B51E82409A008692C7 /* RCTAnimationUtilsTests.m */,
774+
19BA88D41F84344F00741C5A /* RCTBlobManagerTests.m */,
770775
192F69B61E82409A008692C7 /* RCTConvert_YGValueTests.m */,
771776
192F69B71E82409A008692C7 /* RCTNativeAnimatedNodesManagerTests.m */,
772777
13B6C1A21C34225900D3FAF5 /* RCTURLUtilsTests.m */,
@@ -884,6 +889,13 @@
884889
name = Products;
885890
sourceTree = "<group>";
886891
};
892+
19BA89021F8439A700741C5A /* Frameworks */ = {
893+
isa = PBXGroup;
894+
children = (
895+
);
896+
name = Frameworks;
897+
sourceTree = "<group>";
898+
};
887899
272E6B3A1BEA846C001FCF37 /* NativeExampleViews */ = {
888900
isa = PBXGroup;
889901
children = (
@@ -1683,6 +1695,7 @@
16831695
8385CF041B87479200C6273E /* RCTImageLoaderHelpers.m in Sources */,
16841696
192F69B91E82409A008692C7 /* RCTConvert_YGValueTests.m in Sources */,
16851697
BC9C03401DC9F1D600B1C635 /* RCTDevMenuTests.m in Sources */,
1698+
19BA88D51F84344F00741C5A /* RCTBlobManagerTests.m in Sources */,
16861699
68FF44381CF6111500720EFD /* RCTBundleURLProviderTests.m in Sources */,
16871700
8385CEF51B873B5C00C6273E /* RCTImageLoaderTests.m in Sources */,
16881701
);

RNTesterLegacy.xcodeproj/project.pbxproj

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@
9797
2DD323E71DA2DE3F000FE1B8 /* libRCTSettings-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2DD323C81DA2DD8B000FE1B8 /* libRCTSettings-tvOS.a */; };
9898
2DD323E81DA2DE3F000FE1B8 /* libRCTText-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2DD323D01DA2DD8B000FE1B8 /* libRCTText-tvOS.a */; };
9999
2DD323E91DA2DE3F000FE1B8 /* libRCTWebSocket-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2DD323D51DA2DD8B000FE1B8 /* libRCTWebSocket-tvOS.a */; };
100+
2DD323EA1DA2DE3F000FE1B8 /* libReact.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 2DD323D91DA2DD8B000FE1B8 /* libReact.a */; };
100101
3578590A1B28D2CF00341EDB /* libRCTLinking.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 357859011B28D2C500341EDB /* libRCTLinking.a */; };
101102
39AA31A41DC1DFDC000F7EBB /* RCTUnicodeDecodeTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 39AA31A31DC1DFDC000F7EBB /* RCTUnicodeDecodeTests.m */; };
102103
3D05746D1DE6008900184BB4 /* libRCTPushNotification-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3D05746C1DE6008900184BB4 /* libRCTPushNotification-tvOS.a */; };
@@ -117,6 +118,9 @@
117118
83636F8F1B53F22C009F943E /* RCTUIManagerScenarioTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 83636F8E1B53F22C009F943E /* RCTUIManagerScenarioTests.m */; };
118119
8385CEF51B873B5C00C6273E /* RCTImageLoaderTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8385CEF41B873B5C00C6273E /* RCTImageLoaderTests.m */; };
119120
8385CF041B87479200C6273E /* RCTImageLoaderHelpers.m in Sources */ = {isa = PBXBuildFile; fileRef = 8385CF031B87479200C6273E /* RCTImageLoaderHelpers.m */; };
121+
ADAC7A091E093BB900D77272 /* libRCTBlob.a in Frameworks */ = {isa = PBXBuildFile; fileRef = ADBDB9F11DFEC24500ED6528 /* libRCTBlob.a */; };
122+
ADBDBA0D1DFEC24D00ED6528 /* libRCTBlob.a in Frameworks */ = {isa = PBXBuildFile; fileRef = ADBDB9F11DFEC24500ED6528 /* libRCTBlob.a */; };
123+
ADD01A631E093FA900F6D226 /* libRCTBlob-tvOS.a in Frameworks */ = {isa = PBXBuildFile; fileRef = ADD01A471E093FA100F6D226 /* libRCTBlob-tvOS.a */; };
120124
BC9C03401DC9F1D600B1C635 /* RCTDevMenuTests.m in Sources */ = {isa = PBXBuildFile; fileRef = BC9C033F1DC9F1D600B1C635 /* RCTDevMenuTests.m */; };
121125
C654F14C1EB34D0C000B7A9A /* RNTesterTestModule.m in Sources */ = {isa = PBXBuildFile; fileRef = C654F14B1EB34D0C000B7A9A /* RNTesterTestModule.m */; };
122126
C654F16E1EB34D14000B7A9A /* RNTesterTestModule.m in Sources */ = {isa = PBXBuildFile; fileRef = C654F14B1EB34D0C000B7A9A /* RNTesterTestModule.m */; };
@@ -383,6 +387,20 @@
383387
remoteGlobalIDString = 134814201AA4EA6300B7C361;
384388
remoteInfo = RCTSettings;
385389
};
390+
ADBDB9F01DFEC24500ED6528 /* PBXContainerItemProxy */ = {
391+
isa = PBXContainerItemProxy;
392+
containerPortal = ADBDB9E81DFEC24500ED6528 /* RCTBlob.xcodeproj */;
393+
proxyType = 2;
394+
remoteGlobalIDString = 358F4ED71D1E81A9004DF814;
395+
remoteInfo = RCTBlob;
396+
};
397+
ADD01A461E093FA100F6D226 /* PBXContainerItemProxy */ = {
398+
isa = PBXContainerItemProxy;
399+
containerPortal = ADBDB9E81DFEC24500ED6528 /* RCTBlob.xcodeproj */;
400+
proxyType = 2;
401+
remoteGlobalIDString = ADAC7A2E1E093EF800D77272;
402+
remoteInfo = "RCTBlob-tvOS";
403+
};
386404
D85B829B1AB6D5CE003F4FE2 /* PBXContainerItemProxy */ = {
387405
isa = PBXContainerItemProxy;
388406
containerPortal = D85B82911AB6D5CE003F4FE2 /* RCTVibration.xcodeproj */;
@@ -470,6 +488,7 @@
470488
8385CEF41B873B5C00C6273E /* RCTImageLoaderTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTImageLoaderTests.m; sourceTree = "<group>"; };
471489
8385CF031B87479200C6273E /* RCTImageLoaderHelpers.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTImageLoaderHelpers.m; sourceTree = "<group>"; };
472490
8385CF051B8747A000C6273E /* RCTImageLoaderHelpers.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCTImageLoaderHelpers.h; sourceTree = "<group>"; };
491+
ADBDB9E81DFEC24500ED6528 /* RCTBlob.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTBlob.xcodeproj; path = ../../Libraries/Blob/RCTBlob.xcodeproj; sourceTree = "<group>"; };
473492
BC9C033F1DC9F1D600B1C635 /* RCTDevMenuTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTDevMenuTests.m; sourceTree = "<group>"; };
474493
C654F14B1EB34D0C000B7A9A /* RNTesterTestModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNTesterTestModule.m; sourceTree = "<group>"; };
475494
D85B82911AB6D5CE003F4FE2 /* RCTVibration.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = RCTVibration.xcodeproj; path = ../Libraries/Vibration/RCTVibration.xcodeproj; sourceTree = "<group>"; };
@@ -544,6 +563,7 @@
544563
2DD323E61DA2DE3F000FE1B8 /* libRCTNetwork-tvOS.a in Frameworks */,
545564
3D05746D1DE6008900184BB4 /* libRCTPushNotification-tvOS.a in Frameworks */,
546565
2DD323E71DA2DE3F000FE1B8 /* libRCTSettings-tvOS.a in Frameworks */,
566+
ADD01A631E093FA900F6D226 /* libRCTBlob-tvOS.a in Frameworks */,
547567
2DD323E81DA2DE3F000FE1B8 /* libRCTText-tvOS.a in Frameworks */,
548568
2DD323E91DA2DE3F000FE1B8 /* libRCTWebSocket-tvOS.a in Frameworks */,
549569
);
@@ -755,6 +775,21 @@
755775
name = Products;
756776
sourceTree = "<group>";
757777
};
778+
14AADF001AC3DB95002390C9 /* Products */ = {
779+
isa = PBXGroup;
780+
children = (
781+
14AADF041AC3DB95002390C9 /* libReact.a */,
782+
2DD323D91DA2DD8B000FE1B8 /* libReact.a */,
783+
3D3C08811DE3424E00C268FA /* libyoga.a */,
784+
3D3C08831DE3424E00C268FA /* libyoga.a */,
785+
3D05748C1DE6008900184BB4 /* libcxxreact.a */,
786+
3D05748E1DE6008900184BB4 /* libcxxreact.a */,
787+
3D0574901DE6008900184BB4 /* libjschelpers.a */,
788+
3D0574921DE6008900184BB4 /* libjschelpers.a */,
789+
);
790+
name = Products;
791+
sourceTree = "<group>";
792+
};
758793
14D6D6EA1B2205C0001FB087 /* OCMock */ = {
759794
isa = PBXGroup;
760795
children = (
@@ -892,6 +927,15 @@
892927
name = Products;
893928
sourceTree = "<group>";
894929
};
930+
ADBDB9E91DFEC24500ED6528 /* Products */ = {
931+
isa = PBXGroup;
932+
children = (
933+
ADBDB9F11DFEC24500ED6528 /* libRCTBlob.a */,
934+
ADD01A471E093FA100F6D226 /* libRCTBlob-tvOS.a */,
935+
);
936+
name = Products;
937+
sourceTree = "<group>";
938+
};
895939
D85B82921AB6D5CE003F4FE2 /* Products */ = {
896940
isa = PBXGroup;
897941
children = (
@@ -1082,6 +1126,10 @@
10821126
ProductGroup = 13E5019D1D07A502005F35D8 /* Products */;
10831127
ProjectRef = 13E5019C1D07A502005F35D8 /* RCTAnimation.xcodeproj */;
10841128
},
1129+
{
1130+
ProductGroup = ADBDB9E91DFEC24500ED6528 /* Products */;
1131+
ProjectRef = ADBDB9E81DFEC24500ED6528 /* RCTBlob.xcodeproj */;
1132+
},
10851133
{
10861134
ProductGroup = 138DEE031B9EDDDB007F4EA5 /* Products */;
10871135
ProjectRef = 138DEE021B9EDDDB007F4EA5 /* RCTCameraRoll.xcodeproj */;
@@ -1320,6 +1368,13 @@
13201368
remoteRef = 2DD323D41DA2DD8B000FE1B8 /* PBXContainerItemProxy */;
13211369
sourceTree = BUILT_PRODUCTS_DIR;
13221370
};
1371+
2DD323D91DA2DD8B000FE1B8 /* libReact.a */ = {
1372+
isa = PBXReferenceProxy;
1373+
fileType = archive.ar;
1374+
path = libReact.a;
1375+
remoteRef = 2DD323D81DA2DD8B000FE1B8 /* PBXContainerItemProxy */;
1376+
sourceTree = BUILT_PRODUCTS_DIR;
1377+
};
13231378
357859011B28D2C500341EDB /* libRCTLinking.a */ = {
13241379
isa = PBXReferenceProxy;
13251380
fileType = archive.ar;
@@ -1376,6 +1431,20 @@
13761431
remoteRef = 834C36D11AF8DA610019C93C /* PBXContainerItemProxy */;
13771432
sourceTree = BUILT_PRODUCTS_DIR;
13781433
};
1434+
ADBDB9F11DFEC24500ED6528 /* libRCTBlob.a */ = {
1435+
isa = PBXReferenceProxy;
1436+
fileType = archive.ar;
1437+
path = libRCTBlob.a;
1438+
remoteRef = ADBDB9F01DFEC24500ED6528 /* PBXContainerItemProxy */;
1439+
sourceTree = BUILT_PRODUCTS_DIR;
1440+
};
1441+
ADD01A471E093FA100F6D226 /* libRCTBlob-tvOS.a */ = {
1442+
isa = PBXReferenceProxy;
1443+
fileType = archive.ar;
1444+
path = "libRCTBlob-tvOS.a";
1445+
remoteRef = ADD01A461E093FA100F6D226 /* PBXContainerItemProxy */;
1446+
sourceTree = BUILT_PRODUCTS_DIR;
1447+
};
13791448
D85B829C1AB6D5CE003F4FE2 /* libRCTVibration.a */ = {
13801449
isa = PBXReferenceProxy;
13811450
fileType = archive.ar;
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
/**
2+
* Copyright (c) 2015-present, Facebook, Inc.
3+
* All rights reserved.
4+
*
5+
* This source code is licensed under the BSD-style license found in the
6+
* LICENSE file in the root directory of this source tree. An additional grant
7+
* of patent rights can be found in the PATENTS file in the same directory.
8+
*
9+
*/
10+
11+
#import <XCTest/XCTest.h>
12+
13+
#import <RCTBlob/RCTBlobManager.h>
14+
15+
@interface RCTBlobManagerTests : XCTestCase
16+
17+
@end
18+
19+
@implementation RCTBlobManagerTests
20+
{
21+
RCTBlobManager *_module;
22+
NSMutableData *_data;
23+
NSString *_blobId;
24+
}
25+
26+
- (void)setUp
27+
{
28+
[super setUp];
29+
30+
_module = [RCTBlobManager new];
31+
[_module setValue:nil forKey:@"bridge"];
32+
NSInteger size = 120;
33+
_data = [NSMutableData dataWithCapacity:size];
34+
for (NSInteger i = 0; i < size / 4; i++) {
35+
uint32_t randomBits = arc4random();
36+
[_data appendBytes:(void *)&randomBits length:4];
37+
}
38+
_blobId = [NSUUID UUID].UUIDString;
39+
[_module store:_data withId:_blobId];
40+
}
41+
42+
- (void)testResolve
43+
{
44+
XCTAssertTrue([_data isEqualToData:[_module resolve:_blobId offset:0 size:_data.length]]);
45+
NSData *rangeData = [_data subdataWithRange:NSMakeRange(30, _data.length - 30)];
46+
XCTAssertTrue([rangeData isEqualToData:[_module resolve:_blobId offset:30 size:_data.length - 30]]);
47+
}
48+
49+
- (void)testResolveMap
50+
{
51+
NSDictionary<NSString *, id> *map = @{
52+
@"blobId": _blobId,
53+
@"size": @(_data.length),
54+
@"offset": @0,
55+
};
56+
XCTAssertTrue([_data isEqualToData:[_module resolve:map]]);
57+
}
58+
59+
- (void)testResolveURL
60+
{
61+
NSURLComponents *components = [NSURLComponents new];
62+
[components setPath:_blobId];
63+
[components setQuery:[NSString stringWithFormat:@"offset=0&size=%lu", (unsigned long)_data.length]];
64+
XCTAssertTrue([_data isEqualToData:[_module resolveURL:[components URL]]]);
65+
}
66+
67+
- (void)testRemove
68+
{
69+
XCTAssertNotNil([_module resolve:_blobId offset:0 size:_data.length]);
70+
[_module remove:_blobId];
71+
XCTAssertNil([_module resolve:_blobId offset:0 size:_data.length]);
72+
}
73+
74+
- (void)testCreateFromParts
75+
{
76+
NSDictionary<NSString *, id> *blobData = @{
77+
@"blobId": _blobId,
78+
@"offset": @0,
79+
@"size": @(_data.length),
80+
};
81+
NSDictionary<NSString *, id> *blob = @{
82+
@"data": blobData,
83+
@"type": @"blob",
84+
};
85+
NSString *stringData = @"i \u2665 dogs";
86+
NSDictionary<NSString *, id> *string = @{
87+
@"data": stringData,
88+
@"type": @"string",
89+
};
90+
NSString *resultId = [NSUUID UUID].UUIDString;
91+
NSArray<id> *parts = @[blob, string];
92+
93+
[_module createFromParts:parts withId:resultId];
94+
95+
NSMutableData *expectedData = [NSMutableData new];
96+
[expectedData appendData:_data];
97+
[expectedData appendData:[stringData dataUsingEncoding:NSUTF8StringEncoding]];
98+
99+
NSData *result = [_module resolve:resultId offset:0 size:expectedData.length];
100+
101+
XCTAssertTrue([expectedData isEqualToData:result]);
102+
}
103+
104+
@end

0 commit comments

Comments
 (0)