react-native-blob-util 0.22.0 → 0.22.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/.eslintrc.js +56 -56
  2. package/LICENSE +21 -21
  3. package/Migration.md +41 -41
  4. package/NuGet.config +11 -11
  5. package/README.md +1109 -1104
  6. package/android/gradle.properties +1 -1
  7. package/android/src/main/AndroidManifest.xml +37 -37
  8. package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilConfig.java +57 -57
  9. package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilConst.java +20 -20
  10. package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilFileTransformer.java +9 -9
  11. package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilImpl.java +431 -431
  12. package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilProgressConfig.java +39 -39
  13. package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilReq.java +1014 -1014
  14. package/android/src/main/java/com/ReactNativeBlobUtil/Response/ReactNativeBlobUtilDefaultResp.java +98 -98
  15. package/android/src/main/java/com/ReactNativeBlobUtil/Response/ReactNativeBlobUtilFileResp.java +166 -166
  16. package/android/src/main/java/com/ReactNativeBlobUtil/Utils/FileDescription.java +19 -19
  17. package/android/src/main/java/com/ReactNativeBlobUtil/Utils/FileProvider.java +4 -4
  18. package/android/src/main/java/com/ReactNativeBlobUtil/Utils/MimeType.java +70 -70
  19. package/android/src/main/java/com/ReactNativeBlobUtil/Utils/PathResolver.java +223 -223
  20. package/android/src/main/java/com/ReactNativeBlobUtil/Utils/Tls12SocketFactory.java +68 -68
  21. package/android/src/main/res/values/strings.xml +3 -3
  22. package/android/src/main/res/xml/provider_paths.xml +12 -12
  23. package/android.js +58 -58
  24. package/class/ReactNativeBlobUtilCanceledFetchError.js +9 -9
  25. package/class/ReactNativeBlobUtilFile.js +5 -5
  26. package/class/ReactNativeBlobUtilReadStream.js +84 -84
  27. package/class/ReactNativeBlobUtilSession.js +68 -68
  28. package/class/ReactNativeBlobUtilWriteStream.js +50 -50
  29. package/class/StatefulPromise.js +7 -7
  30. package/codegenSpecs/NativeBlobUtils.js +86 -86
  31. package/components/Fetch.onPress.js +10 -10
  32. package/components/Fetch.when.js +15 -15
  33. package/fetch.js +350 -350
  34. package/fs.js +480 -480
  35. package/index.js +64 -64
  36. package/index.js.flow +192 -192
  37. package/index.web.js +1 -1
  38. package/ios/PrivacyInfo.xcprivacy +28 -28
  39. package/ios/ReactNativeBlobUtil/ReactNativeBlobUtil.h +55 -55
  40. package/ios/ReactNativeBlobUtil/ReactNativeBlobUtil.mm +992 -992
  41. package/ios/ReactNativeBlobUtil.xcodeproj/project.pbxproj +405 -405
  42. package/ios/ReactNativeBlobUtilConst.h +58 -58
  43. package/ios/ReactNativeBlobUtilConst.mm +47 -47
  44. package/ios/ReactNativeBlobUtilFS.h +108 -108
  45. package/ios/ReactNativeBlobUtilFS.mm +1064 -1064
  46. package/ios/ReactNativeBlobUtilFileTransformer.h +23 -23
  47. package/ios/ReactNativeBlobUtilFileTransformer.mm +20 -20
  48. package/ios/ReactNativeBlobUtilNetwork.h +49 -49
  49. package/ios/ReactNativeBlobUtilNetwork.mm +159 -159
  50. package/ios/ReactNativeBlobUtilProgress.h +32 -32
  51. package/ios/ReactNativeBlobUtilProgress.mm +57 -57
  52. package/ios/ReactNativeBlobUtilReqBuilder.h +37 -37
  53. package/ios/ReactNativeBlobUtilReqBuilder.mm +292 -292
  54. package/ios/ReactNativeBlobUtilRequest.h +48 -48
  55. package/ios/ReactNativeBlobUtilRequest.mm +584 -584
  56. package/ios.js +61 -61
  57. package/json-stream.js +42 -42
  58. package/lib/oboe-browser.js +2703 -2703
  59. package/mediacollection.js +36 -36
  60. package/package.json +68 -68
  61. package/polyfill/Blob.js +362 -362
  62. package/polyfill/Event.js +11 -11
  63. package/polyfill/EventTarget.js +78 -78
  64. package/polyfill/Fetch.js +219 -219
  65. package/polyfill/File.js +27 -27
  66. package/polyfill/FileReader.js +91 -91
  67. package/polyfill/ProgressEvent.js +32 -32
  68. package/polyfill/XMLHttpRequest.js +466 -466
  69. package/polyfill/XMLHttpRequestEventTarget.js +126 -126
  70. package/polyfill/index.js +11 -11
  71. package/react-native-blob-util.podspec +48 -48
  72. package/types.js +69 -69
  73. package/utils/log.js +40 -40
  74. package/utils/unicode.js +7 -7
  75. package/utils/uri.js +33 -33
  76. package/utils/uuid.js +4 -4
  77. package/windows/ExperimentalFeatures.props +33 -33
  78. package/windows/README.md +2 -2
  79. package/windows/ReactNativeBlobUtil/PropertySheet.props +15 -15
  80. package/windows/ReactNativeBlobUtil/ReactNativeBlobUtil.cpp +1836 -1836
  81. package/windows/ReactNativeBlobUtil/ReactNativeBlobUtil.def +3 -3
  82. package/windows/ReactNativeBlobUtil/ReactNativeBlobUtil.h +372 -372
  83. package/windows/ReactNativeBlobUtil/ReactNativeBlobUtil.vcxproj +139 -139
  84. package/windows/ReactNativeBlobUtil/ReactNativeBlobUtil.vcxproj.filters +43 -43
  85. package/windows/ReactNativeBlobUtil/ReactPackageProvider.cpp +20 -20
  86. package/windows/ReactNativeBlobUtil/ReactPackageProvider.h +24 -24
  87. package/windows/ReactNativeBlobUtil/ReactPackageProvider.idl +9 -9
  88. package/windows/ReactNativeBlobUtil/codegen/.clang-format +1 -1
  89. package/windows/ReactNativeBlobUtil/codegen/NativeBlobUtilsDataTypes.g.h +42 -42
  90. package/windows/ReactNativeBlobUtil/codegen/NativeBlobUtilsSpec.g.h +353 -353
  91. package/windows/ReactNativeBlobUtil/packages.config +3 -3
  92. package/windows/ReactNativeBlobUtil/packages.lock.json +59 -59
  93. package/windows/ReactNativeBlobUtil/pch.cpp +1 -1
  94. package/windows/ReactNativeBlobUtil/pch.h +30 -30
  95. package/windows/ReactNativeBlobUtil/resource.h +5 -5
  96. package/windows/ReactNativeBlobUtil/targetver.h +8 -8
  97. package/windows/ReactNativeBlobUtil.sln +43 -43
@@ -1,292 +1,292 @@
1
- //
2
- // ReactNativeBlobUtilReqBuilder.m
3
- // ReactNativeBlobUtil
4
- //
5
- // Created by Ben Hsieh on 2016/7/9.
6
- // Copyright © 2016年 wkh237. All rights reserved.
7
- //
8
-
9
- #import <Foundation/Foundation.h>
10
- #import "ReactNativeBlobUtilReqBuilder.h"
11
- #import "ReactNativeBlobUtilNetwork.h"
12
- #import "ReactNativeBlobUtilConst.h"
13
- #import "ReactNativeBlobUtilFS.h"
14
-
15
- #if __has_include(<React/RCTAssert.h>)
16
- #import <React/RCTLog.h>
17
- #else
18
- #import "RCTLog.h"
19
- #endif
20
-
21
- @interface ReactNativeBlobUtilReqBuilder()
22
- {
23
-
24
- }
25
- @end
26
-
27
- @implementation ReactNativeBlobUtilReqBuilder
28
-
29
-
30
- // Fetch blob data request
31
- +(void) buildMultipartRequest:(NSDictionary *)options
32
- taskId:(NSString *)taskId
33
- method:(NSString *)method
34
- url:(NSString *)url
35
- headers:(NSDictionary *)headers
36
- form:(NSArray *)form
37
- onComplete:(void(^)(NSURLRequest * req, long bodyLength))onComplete
38
- {
39
- // NSString * encodedUrl = [url stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
40
- NSString * encodedUrl = url;
41
-
42
- // send request
43
- __block NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString: encodedUrl]];
44
- __block NSMutableDictionary *mheaders = [[NSMutableDictionary alloc] initWithDictionary:[ReactNativeBlobUtilNetwork normalizeHeaders:headers]];
45
- NSTimeInterval timeStamp = [[NSDate date] timeIntervalSince1970];
46
- NSNumber * timeStampObj = [NSNumber numberWithDouble: timeStamp];
47
-
48
- // generate boundary
49
- __block NSString * boundary = [NSString stringWithFormat:@"ReactNativeBlobUtil%d", timeStampObj];
50
- dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
51
- __block NSMutableData * postData = [[NSMutableData alloc] init];
52
- // combine multipart/form-data body
53
- [[self class] buildFormBody:form boundary:boundary onComplete:^(NSData *formData, BOOL hasError) {
54
- if(hasError)
55
- {
56
- onComplete(nil, 0);
57
- }
58
- else
59
- {
60
- if(formData != nil)
61
- {
62
- [postData appendData:formData];
63
- // close form data
64
- [postData appendData: [[NSString stringWithFormat:@"--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
65
- [request setHTTPBody:postData];
66
- }
67
- // set content-length
68
- [mheaders setValue:[NSString stringWithFormat:@"%lu",[postData length]] forKey:@"Content-Length"];
69
- [mheaders setValue:@"100-continue" forKey:@"Expect"];
70
- // appaned boundary to content-type
71
- [mheaders setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary] forKey:@"content-type"];
72
- [request setHTTPMethod: method];
73
- [request setAllHTTPHeaderFields:mheaders];
74
- onComplete(request, [formData length]);
75
- }
76
- }];
77
-
78
- });
79
- }
80
-
81
- // Fetch blob data request
82
- +(void) buildOctetRequest:(NSDictionary *)options
83
- taskId:(NSString *)taskId
84
- method:(NSString *)method
85
- url:(NSString *)url
86
- headers:(NSDictionary *)headers
87
- body:(NSString *)body
88
- onComplete:(void(^)(__weak NSURLRequest * req, long bodyLength))onComplete
89
- {
90
- // NSString * encodedUrl = [url stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
91
- NSString * encodedUrl = url;
92
- // send request
93
- __block NSMutableURLRequest *request = [[NSMutableURLRequest alloc]
94
- initWithURL:[NSURL URLWithString: encodedUrl]];
95
-
96
- __block NSMutableDictionary *mheaders = [[NSMutableDictionary alloc] initWithDictionary:[ReactNativeBlobUtilNetwork normalizeHeaders:headers]];
97
- // move heavy task to another thread
98
- dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
99
- NSMutableData * blobData;
100
- long size = -1;
101
- // if method is POST, PUT or PATCH, convert data string format
102
- if([[method lowercaseString] isEqualToString:@"post"] || [[method lowercaseString] isEqualToString:@"put"] || [[method lowercaseString] isEqualToString:@"patch"]) {
103
- // generate octet-stream body
104
- if(body != nil) {
105
- __block NSString * cType = [[self class] getHeaderIgnoreCases:@"content-type" fromHeaders:mheaders];
106
- __block NSString * transferEncoding = [[self class] getHeaderIgnoreCases:@"transfer-encoding" fromHeaders:mheaders];
107
- // when headers does not contain a key named "content-type" (case ignored), use default content type
108
- if(cType == nil)
109
- {
110
- [mheaders setValue:@"application/octet-stream" forKey:@"Content-Type"];
111
- }
112
-
113
- // when body is a string contains file path prefix, try load file from the path
114
- if([body hasPrefix:FILE_PREFIX]) {
115
- __block NSString * orgPath = [body substringFromIndex:[FILE_PREFIX length]];
116
- orgPath = [ReactNativeBlobUtilFS getPathOfAsset:orgPath];
117
- orgPath = [[NSURL URLWithString:orgPath] path];
118
- if([orgPath hasPrefix:AL_PREFIX])
119
- {
120
-
121
- [ReactNativeBlobUtilFS readFile:orgPath encoding:nil transformFile:false onComplete:^(id content, NSString* code, NSString * err) {
122
- if(err != nil)
123
- {
124
- onComplete(nil, 0);
125
- }
126
- else
127
- {
128
- [request setHTTPBody:((NSData *)content)];
129
- [request setHTTPMethod: method];
130
- [request setAllHTTPHeaderFields:mheaders];
131
- onComplete(request, [((NSData *)content) length]);
132
- }
133
- }];
134
-
135
- return;
136
- }
137
- size = [[[NSFileManager defaultManager] attributesOfItemAtPath:orgPath error:nil] fileSize];
138
- if(transferEncoding != nil && [[transferEncoding lowercaseString] isEqualToString:@"chunked"])
139
- {
140
- [request setHTTPBodyStream: [NSInputStream inputStreamWithFileAtPath:orgPath ]];
141
- }
142
- else
143
- {
144
- __block NSData * bodyBytes = [NSData dataWithContentsOfFile:orgPath ];
145
- [request setHTTPBody:bodyBytes];
146
- }
147
- }
148
- // otherwise convert it as BASE64 data string
149
- else {
150
-
151
- __block NSString * cType = [[self class]getHeaderIgnoreCases:@"content-type" fromHeaders:mheaders];
152
- // when content-type is application/octet* decode body string using BASE64 decoder
153
- if([[cType lowercaseString] hasPrefix:@"application/octet"] || [[cType lowercaseString] containsString:@";base64"])
154
- {
155
- __block NSString * ncType = [[cType stringByReplacingOccurrencesOfString:@";base64" withString:@""]stringByReplacingOccurrencesOfString:@";BASE64" withString:@""];
156
- if([mheaders valueForKey:@"content-type"] != nil)
157
- [mheaders setValue:ncType forKey:@"content-type"];
158
- if([mheaders valueForKey:@"Content-Type"] != nil)
159
- [mheaders setValue:ncType forKey:@"Content-Type"];
160
- blobData = [[NSData alloc] initWithBase64EncodedString:body options:0];
161
- [request setHTTPBody:blobData];
162
- size = [blobData length];
163
- }
164
- // otherwise use the body as-is
165
- else
166
- {
167
- size = [body length];
168
- [request setHTTPBody: [body dataUsingEncoding:NSUTF8StringEncoding]];
169
- }
170
- }
171
- }
172
- }
173
-
174
- [request setHTTPMethod: method];
175
- [request setAllHTTPHeaderFields:mheaders];
176
-
177
- onComplete(request, size);
178
- });
179
- }
180
-
181
- +(void) buildFormBody:(NSArray *)form boundary:(NSString *)boundary onComplete:(void(^)(NSData * formData, BOOL hasError))onComplete
182
- {
183
- __block NSMutableData * formData = [[NSMutableData alloc] init];
184
- if(form == nil)
185
- onComplete(nil, NO);
186
- else
187
- {
188
- __block int i = 0;
189
- __block int count = [form count];
190
- // a recursive block that builds multipart body asynchornously
191
- void __block (^getFieldData)(id field) = ^(id field)
192
- {
193
- NSString * name = [field valueForKey:@"name"];
194
- __block NSString * content = [field valueForKey:@"data"];
195
- NSString * contentType = [field valueForKey:@"type"];
196
- // skip when the form field `name` or `data` is empty
197
- if(content == nil || name == nil)
198
- {
199
- i++;
200
- getFieldData([form objectAtIndex:i]);
201
- RCTLogWarn(@"ReactNativeBlobUtil multipart request builder has found a field without `data` or `name` property, the field will be removed implicitly.");
202
- return;
203
- }
204
-
205
- // field is a text field
206
- if([field valueForKey:@"filename"] == nil || content == nil) {
207
- contentType = contentType == nil ? @"text/plain" : contentType;
208
- [formData appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
209
- [formData appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n", name] dataUsingEncoding:NSUTF8StringEncoding]];
210
- [formData appendData:[[NSString stringWithFormat:@"Content-Type: %@\r\n\r\n", contentType] dataUsingEncoding:NSUTF8StringEncoding]];
211
- [formData appendData:[[NSString stringWithFormat:@"%@\r\n", content] dataUsingEncoding:NSUTF8StringEncoding]];
212
- }
213
- // field contains a file
214
- else {
215
- contentType = contentType == nil ? @"application/octet-stream" : contentType;
216
- NSMutableData * blobData;
217
- if(content != nil)
218
- {
219
- // append data from file asynchronously
220
- if([content hasPrefix:FILE_PREFIX])
221
- {
222
- NSString * orgPath = [content substringFromIndex:[FILE_PREFIX length]];
223
- orgPath = [ReactNativeBlobUtilFS getPathOfAsset:orgPath];
224
-
225
- [ReactNativeBlobUtilFS readFile:orgPath encoding:nil transformFile:false onComplete:^(NSData *content, NSString* code, NSString * err) {
226
- if(err != nil)
227
- {
228
- onComplete(formData, YES);
229
- return;
230
- }
231
- NSString * filename = [field valueForKey:@"filename"];
232
- [formData appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
233
- [formData appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n", name, filename] dataUsingEncoding:NSUTF8StringEncoding]];
234
- [formData appendData:[[NSString stringWithFormat:@"Content-Type: %@\r\n\r\n", contentType] dataUsingEncoding:NSUTF8StringEncoding]];
235
- [formData appendData:content];
236
- [formData appendData:[[NSString stringWithFormat:@"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
237
- i++;
238
- if(i < count)
239
- {
240
- __block NSDictionary * nextField = [form objectAtIndex:i];
241
- getFieldData(nextField);
242
- }
243
- else
244
- {
245
- onComplete(formData, NO);
246
- getFieldData = nil;
247
- }
248
- }];
249
- return ;
250
- }
251
- else
252
- blobData = [[NSData alloc] initWithBase64EncodedString:content options:0];
253
- }
254
- NSString * filename = [field valueForKey:@"filename"];
255
- [formData appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
256
- [formData appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n", name, filename] dataUsingEncoding:NSUTF8StringEncoding]];
257
- [formData appendData:[[NSString stringWithFormat:@"Content-Type: %@\r\n\r\n", contentType] dataUsingEncoding:NSUTF8StringEncoding]];
258
- [formData appendData:blobData];
259
- [formData appendData:[[NSString stringWithFormat:@"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
260
- blobData = nil;
261
- }
262
- i++;
263
- if(i < count)
264
- {
265
- __block NSDictionary * nextField = [form objectAtIndex:i];
266
- getFieldData(nextField);
267
- }
268
- else
269
- {
270
- onComplete(formData, NO);
271
- getFieldData = nil;
272
- }
273
-
274
- };
275
- __block NSDictionary * nextField = [form objectAtIndex:i];
276
- getFieldData(nextField);
277
- }
278
- }
279
-
280
- +(NSString *) getHeaderIgnoreCases:(NSString *)field fromHeaders:(NSDictionary *) headers {
281
-
282
- NSString * normalCase = [headers valueForKey:field];
283
- NSString * ignoredCase = [headers valueForKey:[field lowercaseString]];
284
- if( normalCase != nil)
285
- return normalCase;
286
- else
287
- return ignoredCase;
288
-
289
- }
290
-
291
-
292
- @end
1
+ //
2
+ // ReactNativeBlobUtilReqBuilder.m
3
+ // ReactNativeBlobUtil
4
+ //
5
+ // Created by Ben Hsieh on 2016/7/9.
6
+ // Copyright © 2016年 wkh237. All rights reserved.
7
+ //
8
+
9
+ #import <Foundation/Foundation.h>
10
+ #import "ReactNativeBlobUtilReqBuilder.h"
11
+ #import "ReactNativeBlobUtilNetwork.h"
12
+ #import "ReactNativeBlobUtilConst.h"
13
+ #import "ReactNativeBlobUtilFS.h"
14
+
15
+ #if __has_include(<React/RCTAssert.h>)
16
+ #import <React/RCTLog.h>
17
+ #else
18
+ #import "RCTLog.h"
19
+ #endif
20
+
21
+ @interface ReactNativeBlobUtilReqBuilder()
22
+ {
23
+
24
+ }
25
+ @end
26
+
27
+ @implementation ReactNativeBlobUtilReqBuilder
28
+
29
+
30
+ // Fetch blob data request
31
+ +(void) buildMultipartRequest:(NSDictionary *)options
32
+ taskId:(NSString *)taskId
33
+ method:(NSString *)method
34
+ url:(NSString *)url
35
+ headers:(NSDictionary *)headers
36
+ form:(NSArray *)form
37
+ onComplete:(void(^)(NSURLRequest * req, long bodyLength))onComplete
38
+ {
39
+ // NSString * encodedUrl = [url stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
40
+ NSString * encodedUrl = url;
41
+
42
+ // send request
43
+ __block NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString: encodedUrl]];
44
+ __block NSMutableDictionary *mheaders = [[NSMutableDictionary alloc] initWithDictionary:[ReactNativeBlobUtilNetwork normalizeHeaders:headers]];
45
+ NSTimeInterval timeStamp = [[NSDate date] timeIntervalSince1970];
46
+ NSNumber * timeStampObj = [NSNumber numberWithDouble: timeStamp];
47
+
48
+ // generate boundary
49
+ __block NSString * boundary = [NSString stringWithFormat:@"ReactNativeBlobUtil%d", timeStampObj];
50
+ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
51
+ __block NSMutableData * postData = [[NSMutableData alloc] init];
52
+ // combine multipart/form-data body
53
+ [[self class] buildFormBody:form boundary:boundary onComplete:^(NSData *formData, BOOL hasError) {
54
+ if(hasError)
55
+ {
56
+ onComplete(nil, 0);
57
+ }
58
+ else
59
+ {
60
+ if(formData != nil)
61
+ {
62
+ [postData appendData:formData];
63
+ // close form data
64
+ [postData appendData: [[NSString stringWithFormat:@"--%@--\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
65
+ [request setHTTPBody:postData];
66
+ }
67
+ // set content-length
68
+ [mheaders setValue:[NSString stringWithFormat:@"%lu",[postData length]] forKey:@"Content-Length"];
69
+ [mheaders setValue:@"100-continue" forKey:@"Expect"];
70
+ // appaned boundary to content-type
71
+ [mheaders setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary] forKey:@"content-type"];
72
+ [request setHTTPMethod: method];
73
+ [request setAllHTTPHeaderFields:mheaders];
74
+ onComplete(request, [formData length]);
75
+ }
76
+ }];
77
+
78
+ });
79
+ }
80
+
81
+ // Fetch blob data request
82
+ +(void) buildOctetRequest:(NSDictionary *)options
83
+ taskId:(NSString *)taskId
84
+ method:(NSString *)method
85
+ url:(NSString *)url
86
+ headers:(NSDictionary *)headers
87
+ body:(NSString *)body
88
+ onComplete:(void(^)(__weak NSURLRequest * req, long bodyLength))onComplete
89
+ {
90
+ // NSString * encodedUrl = [url stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
91
+ NSString * encodedUrl = url;
92
+ // send request
93
+ __block NSMutableURLRequest *request = [[NSMutableURLRequest alloc]
94
+ initWithURL:[NSURL URLWithString: encodedUrl]];
95
+
96
+ __block NSMutableDictionary *mheaders = [[NSMutableDictionary alloc] initWithDictionary:[ReactNativeBlobUtilNetwork normalizeHeaders:headers]];
97
+ // move heavy task to another thread
98
+ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
99
+ NSMutableData * blobData;
100
+ long size = -1;
101
+ // if method is POST, PUT or PATCH, convert data string format
102
+ if([[method lowercaseString] isEqualToString:@"post"] || [[method lowercaseString] isEqualToString:@"put"] || [[method lowercaseString] isEqualToString:@"patch"]) {
103
+ // generate octet-stream body
104
+ if(body != nil) {
105
+ __block NSString * cType = [[self class] getHeaderIgnoreCases:@"content-type" fromHeaders:mheaders];
106
+ __block NSString * transferEncoding = [[self class] getHeaderIgnoreCases:@"transfer-encoding" fromHeaders:mheaders];
107
+ // when headers does not contain a key named "content-type" (case ignored), use default content type
108
+ if(cType == nil)
109
+ {
110
+ [mheaders setValue:@"application/octet-stream" forKey:@"Content-Type"];
111
+ }
112
+
113
+ // when body is a string contains file path prefix, try load file from the path
114
+ if([body hasPrefix:FILE_PREFIX]) {
115
+ __block NSString * orgPath = [body substringFromIndex:[FILE_PREFIX length]];
116
+ orgPath = [ReactNativeBlobUtilFS getPathOfAsset:orgPath];
117
+ orgPath = [[NSURL URLWithString:orgPath] path];
118
+ if([orgPath hasPrefix:AL_PREFIX])
119
+ {
120
+
121
+ [ReactNativeBlobUtilFS readFile:orgPath encoding:nil transformFile:false onComplete:^(id content, NSString* code, NSString * err) {
122
+ if(err != nil)
123
+ {
124
+ onComplete(nil, 0);
125
+ }
126
+ else
127
+ {
128
+ [request setHTTPBody:((NSData *)content)];
129
+ [request setHTTPMethod: method];
130
+ [request setAllHTTPHeaderFields:mheaders];
131
+ onComplete(request, [((NSData *)content) length]);
132
+ }
133
+ }];
134
+
135
+ return;
136
+ }
137
+ size = [[[NSFileManager defaultManager] attributesOfItemAtPath:orgPath error:nil] fileSize];
138
+ if(transferEncoding != nil && [[transferEncoding lowercaseString] isEqualToString:@"chunked"])
139
+ {
140
+ [request setHTTPBodyStream: [NSInputStream inputStreamWithFileAtPath:orgPath ]];
141
+ }
142
+ else
143
+ {
144
+ __block NSData * bodyBytes = [NSData dataWithContentsOfFile:orgPath ];
145
+ [request setHTTPBody:bodyBytes];
146
+ }
147
+ }
148
+ // otherwise convert it as BASE64 data string
149
+ else {
150
+
151
+ __block NSString * cType = [[self class]getHeaderIgnoreCases:@"content-type" fromHeaders:mheaders];
152
+ // when content-type is application/octet* decode body string using BASE64 decoder
153
+ if([[cType lowercaseString] hasPrefix:@"application/octet"] || [[cType lowercaseString] containsString:@";base64"])
154
+ {
155
+ __block NSString * ncType = [[cType stringByReplacingOccurrencesOfString:@";base64" withString:@""]stringByReplacingOccurrencesOfString:@";BASE64" withString:@""];
156
+ if([mheaders valueForKey:@"content-type"] != nil)
157
+ [mheaders setValue:ncType forKey:@"content-type"];
158
+ if([mheaders valueForKey:@"Content-Type"] != nil)
159
+ [mheaders setValue:ncType forKey:@"Content-Type"];
160
+ blobData = [[NSData alloc] initWithBase64EncodedString:body options:0];
161
+ [request setHTTPBody:blobData];
162
+ size = [blobData length];
163
+ }
164
+ // otherwise use the body as-is
165
+ else
166
+ {
167
+ size = [body length];
168
+ [request setHTTPBody: [body dataUsingEncoding:NSUTF8StringEncoding]];
169
+ }
170
+ }
171
+ }
172
+ }
173
+
174
+ [request setHTTPMethod: method];
175
+ [request setAllHTTPHeaderFields:mheaders];
176
+
177
+ onComplete(request, size);
178
+ });
179
+ }
180
+
181
+ +(void) buildFormBody:(NSArray *)form boundary:(NSString *)boundary onComplete:(void(^)(NSData * formData, BOOL hasError))onComplete
182
+ {
183
+ __block NSMutableData * formData = [[NSMutableData alloc] init];
184
+ if(form == nil)
185
+ onComplete(nil, NO);
186
+ else
187
+ {
188
+ __block int i = 0;
189
+ __block int count = [form count];
190
+ // a recursive block that builds multipart body asynchornously
191
+ void __block (^getFieldData)(id field) = ^(id field)
192
+ {
193
+ NSString * name = [field valueForKey:@"name"];
194
+ __block NSString * content = [field valueForKey:@"data"];
195
+ NSString * contentType = [field valueForKey:@"type"];
196
+ // skip when the form field `name` or `data` is empty
197
+ if(content == nil || name == nil)
198
+ {
199
+ i++;
200
+ getFieldData([form objectAtIndex:i]);
201
+ RCTLogWarn(@"ReactNativeBlobUtil multipart request builder has found a field without `data` or `name` property, the field will be removed implicitly.");
202
+ return;
203
+ }
204
+
205
+ // field is a text field
206
+ if([field valueForKey:@"filename"] == nil || content == nil) {
207
+ contentType = contentType == nil ? @"text/plain" : contentType;
208
+ [formData appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
209
+ [formData appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n", name] dataUsingEncoding:NSUTF8StringEncoding]];
210
+ [formData appendData:[[NSString stringWithFormat:@"Content-Type: %@\r\n\r\n", contentType] dataUsingEncoding:NSUTF8StringEncoding]];
211
+ [formData appendData:[[NSString stringWithFormat:@"%@\r\n", content] dataUsingEncoding:NSUTF8StringEncoding]];
212
+ }
213
+ // field contains a file
214
+ else {
215
+ contentType = contentType == nil ? @"application/octet-stream" : contentType;
216
+ NSMutableData * blobData;
217
+ if(content != nil)
218
+ {
219
+ // append data from file asynchronously
220
+ if([content hasPrefix:FILE_PREFIX])
221
+ {
222
+ NSString * orgPath = [content substringFromIndex:[FILE_PREFIX length]];
223
+ orgPath = [ReactNativeBlobUtilFS getPathOfAsset:orgPath];
224
+
225
+ [ReactNativeBlobUtilFS readFile:orgPath encoding:nil transformFile:false onComplete:^(NSData *content, NSString* code, NSString * err) {
226
+ if(err != nil)
227
+ {
228
+ onComplete(formData, YES);
229
+ return;
230
+ }
231
+ NSString * filename = [field valueForKey:@"filename"];
232
+ [formData appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
233
+ [formData appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n", name, filename] dataUsingEncoding:NSUTF8StringEncoding]];
234
+ [formData appendData:[[NSString stringWithFormat:@"Content-Type: %@\r\n\r\n", contentType] dataUsingEncoding:NSUTF8StringEncoding]];
235
+ [formData appendData:content];
236
+ [formData appendData:[[NSString stringWithFormat:@"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
237
+ i++;
238
+ if(i < count)
239
+ {
240
+ __block NSDictionary * nextField = [form objectAtIndex:i];
241
+ getFieldData(nextField);
242
+ }
243
+ else
244
+ {
245
+ onComplete(formData, NO);
246
+ getFieldData = nil;
247
+ }
248
+ }];
249
+ return ;
250
+ }
251
+ else
252
+ blobData = [[NSData alloc] initWithBase64EncodedString:content options:0];
253
+ }
254
+ NSString * filename = [field valueForKey:@"filename"];
255
+ [formData appendData:[[NSString stringWithFormat:@"--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
256
+ [formData appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n", name, filename] dataUsingEncoding:NSUTF8StringEncoding]];
257
+ [formData appendData:[[NSString stringWithFormat:@"Content-Type: %@\r\n\r\n", contentType] dataUsingEncoding:NSUTF8StringEncoding]];
258
+ [formData appendData:blobData];
259
+ [formData appendData:[[NSString stringWithFormat:@"\r\n"] dataUsingEncoding:NSUTF8StringEncoding]];
260
+ blobData = nil;
261
+ }
262
+ i++;
263
+ if(i < count)
264
+ {
265
+ __block NSDictionary * nextField = [form objectAtIndex:i];
266
+ getFieldData(nextField);
267
+ }
268
+ else
269
+ {
270
+ onComplete(formData, NO);
271
+ getFieldData = nil;
272
+ }
273
+
274
+ };
275
+ __block NSDictionary * nextField = [form objectAtIndex:i];
276
+ getFieldData(nextField);
277
+ }
278
+ }
279
+
280
+ +(NSString *) getHeaderIgnoreCases:(NSString *)field fromHeaders:(NSDictionary *) headers {
281
+
282
+ NSString * normalCase = [headers valueForKey:field];
283
+ NSString * ignoredCase = [headers valueForKey:[field lowercaseString]];
284
+ if( normalCase != nil)
285
+ return normalCase;
286
+ else
287
+ return ignoredCase;
288
+
289
+ }
290
+
291
+
292
+ @end