react-native-blob-util 0.19.0 → 0.19.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 (91) hide show
  1. package/.eslintrc.js +56 -56
  2. package/LICENSE +21 -21
  3. package/Migration.md +41 -41
  4. package/README.md +1071 -1071
  5. package/android/gradle.properties +1 -1
  6. package/android/proguard-rules.pro +17 -17
  7. package/android/src/main/AndroidManifest.xml +39 -40
  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/ReactNativeBlobUtilFS.java +2 -2
  11. package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilFileTransformer.java +9 -9
  12. package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilImpl.java +431 -431
  13. package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilProgressConfig.java +39 -39
  14. package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilReq.java +972 -968
  15. package/android/src/main/java/com/ReactNativeBlobUtil/Response/ReactNativeBlobUtilDefaultResp.java +98 -98
  16. package/android/src/main/java/com/ReactNativeBlobUtil/Response/ReactNativeBlobUtilFileResp.java +157 -157
  17. package/android/src/main/java/com/ReactNativeBlobUtil/Utils/FileDescription.java +19 -19
  18. package/android/src/main/java/com/ReactNativeBlobUtil/Utils/FileProvider.java +4 -4
  19. package/android/src/main/java/com/ReactNativeBlobUtil/Utils/MimeType.java +70 -70
  20. package/android/src/main/java/com/ReactNativeBlobUtil/Utils/PathResolver.java +223 -223
  21. package/android/src/main/java/com/ReactNativeBlobUtil/Utils/Tls12SocketFactory.java +68 -68
  22. package/android/src/main/res/values/strings.xml +3 -3
  23. package/android/src/main/res/xml/provider_paths.xml +12 -12
  24. package/android/src/newarch/java/com/ReactNativeBlobUtil/ReactNativeBlobUtil.java +1 -1
  25. package/android.js +58 -58
  26. package/class/ReactNativeBlobUtilCanceledFetchError.js +9 -9
  27. package/class/ReactNativeBlobUtilFile.js +5 -5
  28. package/class/ReactNativeBlobUtilReadStream.js +84 -84
  29. package/class/ReactNativeBlobUtilSession.js +68 -68
  30. package/class/ReactNativeBlobUtilWriteStream.js +50 -50
  31. package/class/StatefulPromise.js +7 -7
  32. package/codegenSpecs/NativeBlobUtils.js +86 -82
  33. package/components/Fetch.onPress.js +10 -10
  34. package/components/Fetch.when.js +15 -15
  35. package/fetch.js +344 -344
  36. package/fs.js +480 -480
  37. package/index.d.ts +871 -871
  38. package/index.js +64 -64
  39. package/index.js.flow +191 -191
  40. package/index.web.js +1 -1
  41. package/ios/ReactNativeBlobUtil/ReactNativeBlobUtil.h +55 -55
  42. package/ios/ReactNativeBlobUtil/ReactNativeBlobUtil.mm +993 -993
  43. package/ios/ReactNativeBlobUtil.xcodeproj/project.pbxproj +403 -403
  44. package/ios/ReactNativeBlobUtilConst.h +58 -58
  45. package/ios/ReactNativeBlobUtilConst.mm +47 -47
  46. package/ios/ReactNativeBlobUtilFS.h +108 -108
  47. package/ios/ReactNativeBlobUtilFS.mm +977 -977
  48. package/ios/ReactNativeBlobUtilFileTransformer.h +23 -23
  49. package/ios/ReactNativeBlobUtilFileTransformer.mm +20 -20
  50. package/ios/ReactNativeBlobUtilNetwork.h +49 -49
  51. package/ios/ReactNativeBlobUtilNetwork.mm +159 -159
  52. package/ios/ReactNativeBlobUtilProgress.h +32 -32
  53. package/ios/ReactNativeBlobUtilProgress.mm +57 -57
  54. package/ios/ReactNativeBlobUtilReqBuilder.h +37 -37
  55. package/ios/ReactNativeBlobUtilReqBuilder.mm +292 -292
  56. package/ios/ReactNativeBlobUtilRequest.h +48 -48
  57. package/ios/ReactNativeBlobUtilRequest.mm +535 -535
  58. package/ios.js +61 -61
  59. package/json-stream.js +42 -42
  60. package/lib/oboe-browser.js +2703 -2703
  61. package/mediacollection.js +36 -36
  62. package/package.json +55 -55
  63. package/polyfill/Blob.js +362 -362
  64. package/polyfill/Event.js +11 -11
  65. package/polyfill/EventTarget.js +78 -78
  66. package/polyfill/Fetch.js +219 -219
  67. package/polyfill/File.js +27 -27
  68. package/polyfill/FileReader.js +91 -91
  69. package/polyfill/ProgressEvent.js +32 -32
  70. package/polyfill/XMLHttpRequest.js +466 -466
  71. package/polyfill/XMLHttpRequestEventTarget.js +126 -126
  72. package/polyfill/index.js +11 -11
  73. package/react-native-blob-util.podspec +45 -45
  74. package/types.js +69 -69
  75. package/utils/log.js +40 -40
  76. package/utils/unicode.js +7 -7
  77. package/utils/uri.js +33 -33
  78. package/utils/uuid.js +4 -4
  79. package/windows/README.md +2 -2
  80. package/windows/ReactNativeBlobUtil/PropertySheet.props +15 -15
  81. package/windows/ReactNativeBlobUtil/ReactNativeBlobUtil.cpp +1701 -1693
  82. package/windows/ReactNativeBlobUtil/ReactNativeBlobUtil.def +3 -3
  83. package/windows/ReactNativeBlobUtil/ReactNativeBlobUtil.h +379 -366
  84. package/windows/ReactNativeBlobUtil/ReactNativeBlobUtil.vcxproj +181 -181
  85. package/windows/ReactNativeBlobUtil/ReactNativeBlobUtil.vcxproj.filters +31 -31
  86. package/windows/ReactNativeBlobUtil/ReactPackageProvider.cpp +15 -15
  87. package/windows/ReactNativeBlobUtil/ReactPackageProvider.h +20 -20
  88. package/windows/ReactNativeBlobUtil/ReactPackageProvider.idl +9 -9
  89. package/windows/ReactNativeBlobUtil/packages.config +3 -3
  90. package/windows/ReactNativeBlobUtil/pch.cpp +1 -1
  91. package/windows/ReactNativeBlobUtil/pch.h +3 -3
@@ -1,535 +1,535 @@
1
- //
2
- // ReactNativeBlobUtilRequest.m
3
- // ReactNativeBlobUtil
4
- //
5
- // Created by Artur Chrusciel on 15.01.18.
6
- // Copyright © 2018 wkh237.github.io. All rights reserved.
7
- //
8
-
9
- #import "ReactNativeBlobUtilRequest.h"
10
-
11
- #import "ReactNativeBlobUtilFS.h"
12
- #import "ReactNativeBlobUtilConst.h"
13
- #import "ReactNativeBlobUtilFileTransformer.h"
14
- #import "ReactNativeBlobUtilReqBuilder.h"
15
-
16
- #import <CommonCrypto/CommonDigest.h>
17
-
18
-
19
- typedef NS_ENUM(NSUInteger, ResponseFormat) {
20
- UTF8,
21
- BASE64,
22
- AUTO
23
- };
24
-
25
- @interface ReactNativeBlobUtilRequest ()
26
- {
27
- BOOL respFile;
28
- BOOL isNewPart;
29
- BOOL isIncrement;
30
- NSMutableData * partBuffer;
31
- NSString * destPath;
32
- NSOutputStream * writeStream;
33
- long bodyLength;
34
- NSInteger respStatus;
35
- NSMutableArray * redirects;
36
- ResponseFormat responseFormat;
37
- BOOL followRedirect;
38
- BOOL backgroundTask;
39
- }
40
-
41
- @end
42
-
43
- @implementation ReactNativeBlobUtilRequest
44
-
45
- @synthesize taskId;
46
- @synthesize expectedBytes;
47
- @synthesize receivedBytes;
48
- @synthesize respData;
49
- @synthesize callback;
50
- @synthesize baseModule;
51
- @synthesize options;
52
- @synthesize error;
53
-
54
-
55
- - (NSString *)md5:(NSString *)input {
56
- const char* str = [input UTF8String];
57
- unsigned char result[CC_MD5_DIGEST_LENGTH];
58
- CC_MD5(str, (CC_LONG)strlen(str), result);
59
-
60
- NSMutableString *ret = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH*2];
61
- for (int i = 0; i<CC_MD5_DIGEST_LENGTH; i++) {
62
- [ret appendFormat:@"%02x",result[i]];
63
- }
64
- return ret;
65
- }
66
-
67
- // send HTTP request
68
- - (void) sendRequest:(__weak NSDictionary * _Nullable )options
69
- contentLength:(long) contentLength
70
- baseModule:(__strong ReactNativeBlobUtil * _Nullable)baseModule
71
- taskId:(NSString * _Nullable)taskId
72
- withRequest:(__weak NSURLRequest * _Nullable)req
73
- taskOperationQueue:(NSOperationQueue * _Nonnull)operationQueue
74
- callback:(_Nullable RCTResponseSenderBlock) callback
75
- {
76
- self.taskId = taskId;
77
- self.respData = [[NSMutableData alloc] initWithLength:0];
78
- self.callback = callback;
79
- self.baseModule = baseModule;
80
- self.expectedBytes = 0;
81
- self.receivedBytes = 0;
82
- self.options = options;
83
-
84
- backgroundTask = [[options valueForKey:@"IOSBackgroundTask"] boolValue];
85
- // when followRedirect not set in options, defaults to TRUE
86
- followRedirect = [options valueForKey:@"followRedirect"] == nil ? YES : [[options valueForKey:@"followRedirect"] boolValue];
87
- isIncrement = [[options valueForKey:@"increment"] boolValue];
88
- redirects = [[NSMutableArray alloc] init];
89
-
90
- if (req.URL) {
91
- [redirects addObject:req.URL.absoluteString];
92
- }
93
-
94
- // set response format
95
- NSString * rnfbResp = [req.allHTTPHeaderFields valueForKey:@"RNFB-Response"];
96
-
97
- if ([[rnfbResp lowercaseString] isEqualToString:@"base64"]) {
98
- responseFormat = BASE64;
99
- } else if ([[rnfbResp lowercaseString] isEqualToString:@"utf8"]) {
100
- responseFormat = UTF8;
101
- } else {
102
- responseFormat = AUTO;
103
- }
104
-
105
- NSString * path = [self.options valueForKey:CONFIG_FILE_PATH];
106
- NSString * key = [self.options valueForKey:CONFIG_KEY];
107
- NSURLSession * session;
108
-
109
- bodyLength = contentLength;
110
-
111
- // the session trust any SSL certification
112
- NSURLSessionConfiguration *defaultConfigObject;
113
-
114
- defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
115
-
116
- if (backgroundTask) {
117
- defaultConfigObject = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:taskId];
118
- }
119
-
120
- // request timeout, -1 if not set in options
121
- float timeout = [options valueForKey:@"timeout"] == nil ? -1 : [[options valueForKey:@"timeout"] floatValue];
122
-
123
- if (timeout > 0) {
124
- defaultConfigObject.timeoutIntervalForRequest = timeout/1000;
125
- }
126
-
127
- if([options valueForKey:CONFIG_WIFI_ONLY] != nil && ![options[CONFIG_WIFI_ONLY] boolValue]){
128
- [defaultConfigObject setAllowsCellularAccess:NO];
129
- }
130
-
131
- defaultConfigObject.HTTPMaximumConnectionsPerHost = 10;
132
- session = [NSURLSession sessionWithConfiguration:defaultConfigObject delegate:self delegateQueue:operationQueue];
133
-
134
- if (path || [self.options valueForKey:CONFIG_USE_TEMP]) {
135
- respFile = YES;
136
-
137
- NSString* cacheKey = taskId;
138
- if (key) {
139
- cacheKey = [self md5:key];
140
-
141
- if (!cacheKey) {
142
- cacheKey = taskId;
143
- }
144
-
145
- destPath = [ReactNativeBlobUtilFS getTempPath:cacheKey withExtension:[self.options valueForKey:CONFIG_FILE_EXT]];
146
-
147
- if ([[NSFileManager defaultManager] fileExistsAtPath:destPath]) {
148
- callback(@[[NSNull null], RESP_TYPE_PATH, destPath]);
149
-
150
- return;
151
- }
152
- }
153
-
154
- if (path) {
155
- destPath = path;
156
- } else {
157
- destPath = [ReactNativeBlobUtilFS getTempPath:cacheKey withExtension:[self.options valueForKey:CONFIG_FILE_EXT]];
158
- }
159
-
160
- // We still need to initialize this as a placeholder in memory before we perform
161
- // the conversion
162
- if ([self ShouldTransformFile]) {
163
- respData = [[NSMutableData alloc] init];
164
- }
165
- } else {
166
- respData = [[NSMutableData alloc] init];
167
- respFile = NO;
168
- }
169
-
170
- NSURLSessionDataTask *task = [session dataTaskWithRequest:req];
171
- [task resume];
172
- self.task = task;
173
-
174
- // network status indicator
175
- if ([[options objectForKey:CONFIG_INDICATOR] boolValue]) {
176
- dispatch_async(dispatch_get_main_queue(), ^{
177
- [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
178
- });
179
- }
180
- }
181
-
182
- ////////////////////////////////////////
183
- //
184
- // NSURLSession delegates
185
- //
186
- ////////////////////////////////////////
187
-
188
-
189
- #pragma mark NSURLSession delegate methods
190
-
191
-
192
- #pragma mark - Received Response
193
- // set expected content length on response received
194
- - (void) URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler
195
- {
196
- expectedBytes = [response expectedContentLength];
197
-
198
- NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response;
199
- NSInteger statusCode = [(NSHTTPURLResponse *)response statusCode];
200
- NSString * respType = @"";
201
- respStatus = statusCode;
202
-
203
- if ([response respondsToSelector:@selector(allHeaderFields)])
204
- {
205
- NSDictionary *headers = [httpResponse allHeaderFields];
206
- NSString * respCType = [[ReactNativeBlobUtilReqBuilder getHeaderIgnoreCases:@"Content-Type" fromHeaders:headers] lowercaseString];
207
-
208
- if (self.isServerPush) {
209
- if (partBuffer) {
210
- [self.baseModule
211
- emitEventDict:EVENT_SERVER_PUSH
212
- body:@{
213
- @"taskId": taskId,
214
- @"chunk": [partBuffer base64EncodedStringWithOptions:0],
215
- }
216
- ];
217
- }
218
-
219
- partBuffer = [[NSMutableData alloc] init];
220
- completionHandler(NSURLSessionResponseAllow);
221
-
222
- return;
223
- } else {
224
- self.isServerPush = [[respCType lowercaseString] containsString:@"multipart/x-mixed-replace;"];
225
- }
226
-
227
- if(respCType)
228
- {
229
- NSArray * extraBlobCTypes = [options objectForKey:CONFIG_EXTRA_BLOB_CTYPE];
230
-
231
- if ([respCType containsString:@"text/"]) {
232
- respType = @"text";
233
- } else if ([respCType containsString:@"application/json"]) {
234
- respType = @"json";
235
- } else if(extraBlobCTypes) { // If extra blob content type is not empty, check if response type matches
236
- for (NSString * substr in extraBlobCTypes) {
237
- if ([respCType containsString:[substr lowercaseString]]) {
238
- respType = @"blob";
239
- respFile = YES;
240
- destPath = [ReactNativeBlobUtilFS getTempPath:taskId withExtension:nil];
241
- break;
242
- }
243
- }
244
- } else {
245
- respType = @"blob";
246
-
247
- // for XMLHttpRequest, switch response data handling strategy automatically
248
- if ([options valueForKey:@"auto"]) {
249
- respFile = YES;
250
- destPath = [ReactNativeBlobUtilFS getTempPath:taskId withExtension:@""];
251
- }
252
- }
253
- } else {
254
- respType = @"text";
255
- }
256
-
257
- #pragma mark - handling cookies
258
- // # 153 get cookies
259
- if (response.URL) {
260
- NSHTTPCookieStorage * cookieStore = [NSHTTPCookieStorage sharedHTTPCookieStorage];
261
- NSArray<NSHTTPCookie *> * cookies = [NSHTTPCookie cookiesWithResponseHeaderFields: headers forURL:response.URL];
262
- if (cookies.count) {
263
- [cookieStore setCookies:cookies forURL:response.URL mainDocumentURL:nil];
264
- }
265
- }
266
- [self.baseModule emitEventDict : EVENT_STATE_CHANGE
267
- body:@{
268
- @"taskId": taskId,
269
- @"state": @"2",
270
- @"headers": headers,
271
- @"redirects": redirects,
272
- @"respType" : respType,
273
- @"timeout" : @NO,
274
- @"status": [NSNumber numberWithInteger:statusCode]
275
- }
276
- ];
277
- } else {
278
- NSLog(@"oops");
279
- }
280
-
281
- if (respFile)
282
- {
283
- @try{
284
- NSFileManager * fm = [NSFileManager defaultManager];
285
- NSString * folder = [destPath stringByDeletingLastPathComponent];
286
-
287
- if (![fm fileExistsAtPath:folder]) {
288
- [fm createDirectoryAtPath:folder withIntermediateDirectories:YES attributes:NULL error:nil];
289
- }
290
-
291
- // if not set overwrite in options, defaults to TRUE
292
- BOOL overwrite = [options valueForKey:@"overwrite"] == nil ? YES : [[options valueForKey:@"overwrite"] boolValue];
293
- BOOL appendToExistingFile = [destPath containsString:@"?append=true"];
294
-
295
- appendToExistingFile = !overwrite;
296
-
297
- // For solving #141 append response data if the file already exists
298
- // base on PR#139 @kejinliang
299
- if (appendToExistingFile) {
300
- destPath = [destPath stringByReplacingOccurrencesOfString:@"?append=true" withString:@""];
301
- }
302
-
303
- if (![fm fileExistsAtPath:destPath]) {
304
- [fm createFileAtPath:destPath contents:[[NSData alloc] init] attributes:nil];
305
- }
306
-
307
- writeStream = [[NSOutputStream alloc] initToFileAtPath:destPath append:appendToExistingFile];
308
- [writeStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
309
- [writeStream open];
310
- }
311
- @catch(NSException * ex)
312
- {
313
- NSLog(@"write file error");
314
- }
315
- }
316
-
317
- completionHandler(NSURLSessionResponseAllow);
318
- }
319
-
320
-
321
- // download progress handler
322
- - (void) URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data
323
- {
324
- // For #143 handling multipart/x-mixed-replace response
325
- if (self.isServerPush)
326
- {
327
- [partBuffer appendData:data];
328
-
329
- return ;
330
- }
331
-
332
- NSNumber * received = [NSNumber numberWithLong:[data length]];
333
- receivedBytes += [received longValue];
334
- NSString * chunkString = @"";
335
-
336
- if (isIncrement) {
337
- chunkString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
338
- }
339
-
340
- // If we need to process the data, we defer writing into the file until the we have all the data, at which point
341
- // we can perform the processing and then write into the file
342
- if (respFile && ![self ShouldTransformFile]) {
343
- [writeStream write:(const uint8_t *)[data bytes] maxLength:[data length]];
344
- } else {
345
- [respData appendData:data];
346
- }
347
-
348
- if (expectedBytes == 0) {
349
- return;
350
- }
351
-
352
- // For non-chunked download, progress is received / expected
353
- // For chunked download, progress can be either 0 (started) or 1 (ended)
354
- NSNumber *now;
355
- if (expectedBytes != NSURLResponseUnknownLength) {
356
- now = [NSNumber numberWithFloat:((float)receivedBytes/(float)expectedBytes)];
357
- } else {
358
- now = @0;
359
- }
360
-
361
- if ([self.progressConfig shouldReport:now]) {
362
- NSDictionary *body;
363
- if (expectedBytes == NSURLResponseUnknownLength) {
364
- // For chunked downloads
365
- body = @{
366
- @"taskId": taskId,
367
- @"written": [NSString stringWithFormat:@"%d", 0],
368
- @"total": [NSString stringWithFormat:@"%lld", (long long) expectedBytes],
369
- @"chunk": chunkString,
370
- };
371
- } else {
372
- // For non-chunked downloads
373
- body = @{
374
- @"taskId": taskId,
375
- @"written": [NSString stringWithFormat:@"%lld", (long long) receivedBytes],
376
- @"total": [NSString stringWithFormat:@"%lld", (long long) expectedBytes],
377
- @"chunk": chunkString,
378
- };
379
- }
380
- [self.baseModule emitEventDict:EVENT_PROGRESS body:body];
381
- }
382
- }
383
-
384
- - (void) URLSession:(NSURLSession *)session didBecomeInvalidWithError:(nullable NSError *)error
385
- {
386
- if ([session isEqual:session]) {
387
- session = nil;
388
- }
389
- }
390
-
391
-
392
- - (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
393
- {
394
-
395
- self.error = error;
396
- NSString * errMsg;
397
- NSString * respStr;
398
- NSString * rnfbRespType;
399
-
400
- // only run this if we were requested to change it
401
- if ([[options objectForKey:CONFIG_INDICATOR] boolValue]) {
402
- dispatch_async(dispatch_get_main_queue(), ^{
403
- [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
404
- });
405
- }
406
-
407
- if (error) {
408
- if (error.domain == NSURLErrorDomain && error.code == NSURLErrorCancelled) {
409
- errMsg = @"task cancelled";
410
- } else {
411
- errMsg = [error localizedDescription];
412
- }
413
- } else if ([self.progressConfig shouldReport:@1] && expectedBytes == NSURLResponseUnknownLength) {
414
- // For chunked downloads
415
- [self.baseModule emitEventDict:EVENT_PROGRESS body:@{
416
- @"taskId": taskId,
417
- @"written": [NSString stringWithFormat:@"%lld", (long long) receivedBytes],
418
- @"total": [NSString stringWithFormat:@"%lld", (long long) receivedBytes],
419
- @"chunk": @"",
420
- }];
421
- }
422
-
423
- if (respFile) {
424
- if ([self ShouldTransformFile]) {
425
- // At this point, we have the data that we deferred to write into a file. We can now
426
- // perform the conversion and write the converted data into the file.
427
- NSObject<FileTransformer>* fileTransformer = [ReactNativeBlobUtilFileTransformer getFileTransformer];
428
- if (!fileTransformer) {
429
- errMsg = @"Transform file specified but file transfomer not set";
430
- } else {
431
- @try{
432
- NSData* transformedData = [fileTransformer onWriteFile:respData];
433
- [writeStream write:(const uint8_t *)[transformedData bytes] maxLength:[transformedData length]];
434
- } @catch(NSException * ex)
435
- {
436
- errMsg = [NSString stringWithFormat:@"Exception on File Transformer: '%@' ", [ex description]];
437
- }
438
- }
439
- }
440
- [writeStream close];
441
- rnfbRespType = RESP_TYPE_PATH;
442
- respStr = destPath;
443
- } else { // base64 response
444
- // #73 fix unicode data encoding issue :
445
- // when response type is BASE64, we should first try to encode the response data to UTF8 format
446
- // if it turns out not to be `nil` that means the response data contains valid UTF8 string,
447
- // in order to properly encode the UTF8 string, use URL encoding before BASE64 encoding.
448
- NSString * utf8 = [[NSString alloc] initWithData:respData encoding:NSUTF8StringEncoding];
449
-
450
- if (responseFormat == BASE64) {
451
- rnfbRespType = RESP_TYPE_BASE64;
452
- respStr = [respData base64EncodedStringWithOptions:0];
453
- } else if (responseFormat == UTF8) {
454
- rnfbRespType = RESP_TYPE_UTF8;
455
- respStr = utf8;
456
- } else {
457
- if (utf8) {
458
- rnfbRespType = RESP_TYPE_UTF8;
459
- respStr = utf8;
460
- } else {
461
- rnfbRespType = RESP_TYPE_BASE64;
462
- respStr = [respData base64EncodedStringWithOptions:0];
463
- }
464
- }
465
- }
466
-
467
-
468
- callback(@[
469
- errMsg ?: [NSNull null],
470
- rnfbRespType ?: @"",
471
- respStr ?: [NSNull null]
472
- ]);
473
-
474
- respData = nil;
475
- receivedBytes = 0;
476
- [session finishTasksAndInvalidate];
477
-
478
- }
479
-
480
- - (BOOL) ShouldTransformFile{
481
- return [[options valueForKey:CONFIG_TRANSFORM_FILE] boolValue];
482
- }
483
-
484
- // upload progress handler
485
- - (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didSendBodyData:(int64_t)bytesSent totalBytesSent:(int64_t)totalBytesWritten totalBytesExpectedToSend:(int64_t)totalBytesExpectedToWrite
486
- {
487
- if (totalBytesExpectedToWrite == 0) {
488
- return;
489
- }
490
-
491
- NSNumber * now = [NSNumber numberWithFloat:((float)totalBytesWritten/(float)totalBytesExpectedToWrite)];
492
-
493
- if ([self.uploadProgressConfig shouldReport:now]) {
494
- [self.baseModule emitEventDict:EVENT_PROGRESS_UPLOAD
495
- body:@{
496
- @"taskId": taskId,
497
- @"written": [NSString stringWithFormat:@"%ld", (long) totalBytesWritten],
498
- @"total": [NSString stringWithFormat:@"%ld", (long) totalBytesExpectedToWrite]
499
- }
500
- ];
501
- }
502
- }
503
-
504
-
505
- - (void) URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable credantial))completionHandler
506
- {
507
- if ([[options valueForKey:CONFIG_TRUSTY] boolValue]) {
508
- completionHandler(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]);
509
- } else {
510
- completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]);
511
- }
512
- }
513
-
514
-
515
- - (void) URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session
516
- {
517
- NSLog(@"sess done in background");
518
- }
519
-
520
- - (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task willPerformHTTPRedirection:(NSHTTPURLResponse *)response newRequest:(NSURLRequest *)request completionHandler:(void (^)(NSURLRequest * _Nullable))completionHandler
521
- {
522
-
523
- if (followRedirect) {
524
- if (request.URL) {
525
- [redirects addObject:[request.URL absoluteString]];
526
- }
527
-
528
- completionHandler(request);
529
- } else {
530
- completionHandler(nil);
531
- }
532
- }
533
-
534
-
535
- @end
1
+ //
2
+ // ReactNativeBlobUtilRequest.m
3
+ // ReactNativeBlobUtil
4
+ //
5
+ // Created by Artur Chrusciel on 15.01.18.
6
+ // Copyright © 2018 wkh237.github.io. All rights reserved.
7
+ //
8
+
9
+ #import "ReactNativeBlobUtilRequest.h"
10
+
11
+ #import "ReactNativeBlobUtilFS.h"
12
+ #import "ReactNativeBlobUtilConst.h"
13
+ #import "ReactNativeBlobUtilFileTransformer.h"
14
+ #import "ReactNativeBlobUtilReqBuilder.h"
15
+
16
+ #import <CommonCrypto/CommonDigest.h>
17
+
18
+
19
+ typedef NS_ENUM(NSUInteger, ResponseFormat) {
20
+ UTF8,
21
+ BASE64,
22
+ AUTO
23
+ };
24
+
25
+ @interface ReactNativeBlobUtilRequest ()
26
+ {
27
+ BOOL respFile;
28
+ BOOL isNewPart;
29
+ BOOL isIncrement;
30
+ NSMutableData * partBuffer;
31
+ NSString * destPath;
32
+ NSOutputStream * writeStream;
33
+ long bodyLength;
34
+ NSInteger respStatus;
35
+ NSMutableArray * redirects;
36
+ ResponseFormat responseFormat;
37
+ BOOL followRedirect;
38
+ BOOL backgroundTask;
39
+ }
40
+
41
+ @end
42
+
43
+ @implementation ReactNativeBlobUtilRequest
44
+
45
+ @synthesize taskId;
46
+ @synthesize expectedBytes;
47
+ @synthesize receivedBytes;
48
+ @synthesize respData;
49
+ @synthesize callback;
50
+ @synthesize baseModule;
51
+ @synthesize options;
52
+ @synthesize error;
53
+
54
+
55
+ - (NSString *)md5:(NSString *)input {
56
+ const char* str = [input UTF8String];
57
+ unsigned char result[CC_MD5_DIGEST_LENGTH];
58
+ CC_MD5(str, (CC_LONG)strlen(str), result);
59
+
60
+ NSMutableString *ret = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH*2];
61
+ for (int i = 0; i<CC_MD5_DIGEST_LENGTH; i++) {
62
+ [ret appendFormat:@"%02x",result[i]];
63
+ }
64
+ return ret;
65
+ }
66
+
67
+ // send HTTP request
68
+ - (void) sendRequest:(__weak NSDictionary * _Nullable )options
69
+ contentLength:(long) contentLength
70
+ baseModule:(__strong ReactNativeBlobUtil * _Nullable)baseModule
71
+ taskId:(NSString * _Nullable)taskId
72
+ withRequest:(__weak NSURLRequest * _Nullable)req
73
+ taskOperationQueue:(NSOperationQueue * _Nonnull)operationQueue
74
+ callback:(_Nullable RCTResponseSenderBlock) callback
75
+ {
76
+ self.taskId = taskId;
77
+ self.respData = [[NSMutableData alloc] initWithLength:0];
78
+ self.callback = callback;
79
+ self.baseModule = baseModule;
80
+ self.expectedBytes = 0;
81
+ self.receivedBytes = 0;
82
+ self.options = options;
83
+
84
+ backgroundTask = [[options valueForKey:@"IOSBackgroundTask"] boolValue];
85
+ // when followRedirect not set in options, defaults to TRUE
86
+ followRedirect = [options valueForKey:@"followRedirect"] == nil ? YES : [[options valueForKey:@"followRedirect"] boolValue];
87
+ isIncrement = [[options valueForKey:@"increment"] boolValue];
88
+ redirects = [[NSMutableArray alloc] init];
89
+
90
+ if (req.URL) {
91
+ [redirects addObject:req.URL.absoluteString];
92
+ }
93
+
94
+ // set response format
95
+ NSString * rnfbResp = [req.allHTTPHeaderFields valueForKey:@"RNFB-Response"];
96
+
97
+ if ([[rnfbResp lowercaseString] isEqualToString:@"base64"]) {
98
+ responseFormat = BASE64;
99
+ } else if ([[rnfbResp lowercaseString] isEqualToString:@"utf8"]) {
100
+ responseFormat = UTF8;
101
+ } else {
102
+ responseFormat = AUTO;
103
+ }
104
+
105
+ NSString * path = [self.options valueForKey:CONFIG_FILE_PATH];
106
+ NSString * key = [self.options valueForKey:CONFIG_KEY];
107
+ NSURLSession * session;
108
+
109
+ bodyLength = contentLength;
110
+
111
+ // the session trust any SSL certification
112
+ NSURLSessionConfiguration *defaultConfigObject;
113
+
114
+ defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
115
+
116
+ if (backgroundTask) {
117
+ defaultConfigObject = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:taskId];
118
+ }
119
+
120
+ // request timeout, -1 if not set in options
121
+ float timeout = [options valueForKey:@"timeout"] == nil ? -1 : [[options valueForKey:@"timeout"] floatValue];
122
+
123
+ if (timeout > 0) {
124
+ defaultConfigObject.timeoutIntervalForRequest = timeout/1000;
125
+ }
126
+
127
+ if([options valueForKey:CONFIG_WIFI_ONLY] != nil && ![options[CONFIG_WIFI_ONLY] boolValue]){
128
+ [defaultConfigObject setAllowsCellularAccess:NO];
129
+ }
130
+
131
+ defaultConfigObject.HTTPMaximumConnectionsPerHost = 10;
132
+ session = [NSURLSession sessionWithConfiguration:defaultConfigObject delegate:self delegateQueue:operationQueue];
133
+
134
+ if (path || [self.options valueForKey:CONFIG_USE_TEMP]) {
135
+ respFile = YES;
136
+
137
+ NSString* cacheKey = taskId;
138
+ if (key) {
139
+ cacheKey = [self md5:key];
140
+
141
+ if (!cacheKey) {
142
+ cacheKey = taskId;
143
+ }
144
+
145
+ destPath = [ReactNativeBlobUtilFS getTempPath:cacheKey withExtension:[self.options valueForKey:CONFIG_FILE_EXT]];
146
+
147
+ if ([[NSFileManager defaultManager] fileExistsAtPath:destPath]) {
148
+ callback(@[[NSNull null], RESP_TYPE_PATH, destPath]);
149
+
150
+ return;
151
+ }
152
+ }
153
+
154
+ if (path) {
155
+ destPath = path;
156
+ } else {
157
+ destPath = [ReactNativeBlobUtilFS getTempPath:cacheKey withExtension:[self.options valueForKey:CONFIG_FILE_EXT]];
158
+ }
159
+
160
+ // We still need to initialize this as a placeholder in memory before we perform
161
+ // the conversion
162
+ if ([self ShouldTransformFile]) {
163
+ respData = [[NSMutableData alloc] init];
164
+ }
165
+ } else {
166
+ respData = [[NSMutableData alloc] init];
167
+ respFile = NO;
168
+ }
169
+
170
+ NSURLSessionDataTask *task = [session dataTaskWithRequest:req];
171
+ [task resume];
172
+ self.task = task;
173
+
174
+ // network status indicator
175
+ if ([[options objectForKey:CONFIG_INDICATOR] boolValue]) {
176
+ dispatch_async(dispatch_get_main_queue(), ^{
177
+ [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
178
+ });
179
+ }
180
+ }
181
+
182
+ ////////////////////////////////////////
183
+ //
184
+ // NSURLSession delegates
185
+ //
186
+ ////////////////////////////////////////
187
+
188
+
189
+ #pragma mark NSURLSession delegate methods
190
+
191
+
192
+ #pragma mark - Received Response
193
+ // set expected content length on response received
194
+ - (void) URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler
195
+ {
196
+ expectedBytes = [response expectedContentLength];
197
+
198
+ NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse*)response;
199
+ NSInteger statusCode = [(NSHTTPURLResponse *)response statusCode];
200
+ NSString * respType = @"";
201
+ respStatus = statusCode;
202
+
203
+ if ([response respondsToSelector:@selector(allHeaderFields)])
204
+ {
205
+ NSDictionary *headers = [httpResponse allHeaderFields];
206
+ NSString * respCType = [[ReactNativeBlobUtilReqBuilder getHeaderIgnoreCases:@"Content-Type" fromHeaders:headers] lowercaseString];
207
+
208
+ if (self.isServerPush) {
209
+ if (partBuffer) {
210
+ [self.baseModule
211
+ emitEventDict:EVENT_SERVER_PUSH
212
+ body:@{
213
+ @"taskId": taskId,
214
+ @"chunk": [partBuffer base64EncodedStringWithOptions:0],
215
+ }
216
+ ];
217
+ }
218
+
219
+ partBuffer = [[NSMutableData alloc] init];
220
+ completionHandler(NSURLSessionResponseAllow);
221
+
222
+ return;
223
+ } else {
224
+ self.isServerPush = [[respCType lowercaseString] containsString:@"multipart/x-mixed-replace;"];
225
+ }
226
+
227
+ if(respCType)
228
+ {
229
+ NSArray * extraBlobCTypes = [options objectForKey:CONFIG_EXTRA_BLOB_CTYPE];
230
+
231
+ if ([respCType containsString:@"text/"]) {
232
+ respType = @"text";
233
+ } else if ([respCType containsString:@"application/json"]) {
234
+ respType = @"json";
235
+ } else if(extraBlobCTypes) { // If extra blob content type is not empty, check if response type matches
236
+ for (NSString * substr in extraBlobCTypes) {
237
+ if ([respCType containsString:[substr lowercaseString]]) {
238
+ respType = @"blob";
239
+ respFile = YES;
240
+ destPath = [ReactNativeBlobUtilFS getTempPath:taskId withExtension:nil];
241
+ break;
242
+ }
243
+ }
244
+ } else {
245
+ respType = @"blob";
246
+
247
+ // for XMLHttpRequest, switch response data handling strategy automatically
248
+ if ([options valueForKey:@"auto"]) {
249
+ respFile = YES;
250
+ destPath = [ReactNativeBlobUtilFS getTempPath:taskId withExtension:@""];
251
+ }
252
+ }
253
+ } else {
254
+ respType = @"text";
255
+ }
256
+
257
+ #pragma mark - handling cookies
258
+ // # 153 get cookies
259
+ if (response.URL) {
260
+ NSHTTPCookieStorage * cookieStore = [NSHTTPCookieStorage sharedHTTPCookieStorage];
261
+ NSArray<NSHTTPCookie *> * cookies = [NSHTTPCookie cookiesWithResponseHeaderFields: headers forURL:response.URL];
262
+ if (cookies.count) {
263
+ [cookieStore setCookies:cookies forURL:response.URL mainDocumentURL:nil];
264
+ }
265
+ }
266
+ [self.baseModule emitEventDict : EVENT_STATE_CHANGE
267
+ body:@{
268
+ @"taskId": taskId,
269
+ @"state": @"2",
270
+ @"headers": headers,
271
+ @"redirects": redirects,
272
+ @"respType" : respType,
273
+ @"timeout" : @NO,
274
+ @"status": [NSNumber numberWithInteger:statusCode]
275
+ }
276
+ ];
277
+ } else {
278
+ NSLog(@"oops");
279
+ }
280
+
281
+ if (respFile)
282
+ {
283
+ @try{
284
+ NSFileManager * fm = [NSFileManager defaultManager];
285
+ NSString * folder = [destPath stringByDeletingLastPathComponent];
286
+
287
+ if (![fm fileExistsAtPath:folder]) {
288
+ [fm createDirectoryAtPath:folder withIntermediateDirectories:YES attributes:NULL error:nil];
289
+ }
290
+
291
+ // if not set overwrite in options, defaults to TRUE
292
+ BOOL overwrite = [options valueForKey:@"overwrite"] == nil ? YES : [[options valueForKey:@"overwrite"] boolValue];
293
+ BOOL appendToExistingFile = [destPath containsString:@"?append=true"];
294
+
295
+ appendToExistingFile = !overwrite;
296
+
297
+ // For solving #141 append response data if the file already exists
298
+ // base on PR#139 @kejinliang
299
+ if (appendToExistingFile) {
300
+ destPath = [destPath stringByReplacingOccurrencesOfString:@"?append=true" withString:@""];
301
+ }
302
+
303
+ if (![fm fileExistsAtPath:destPath]) {
304
+ [fm createFileAtPath:destPath contents:[[NSData alloc] init] attributes:nil];
305
+ }
306
+
307
+ writeStream = [[NSOutputStream alloc] initToFileAtPath:destPath append:appendToExistingFile];
308
+ [writeStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
309
+ [writeStream open];
310
+ }
311
+ @catch(NSException * ex)
312
+ {
313
+ NSLog(@"write file error");
314
+ }
315
+ }
316
+
317
+ completionHandler(NSURLSessionResponseAllow);
318
+ }
319
+
320
+
321
+ // download progress handler
322
+ - (void) URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data
323
+ {
324
+ // For #143 handling multipart/x-mixed-replace response
325
+ if (self.isServerPush)
326
+ {
327
+ [partBuffer appendData:data];
328
+
329
+ return ;
330
+ }
331
+
332
+ NSNumber * received = [NSNumber numberWithLong:[data length]];
333
+ receivedBytes += [received longValue];
334
+ NSString * chunkString = @"";
335
+
336
+ if (isIncrement) {
337
+ chunkString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
338
+ }
339
+
340
+ // If we need to process the data, we defer writing into the file until the we have all the data, at which point
341
+ // we can perform the processing and then write into the file
342
+ if (respFile && ![self ShouldTransformFile]) {
343
+ [writeStream write:(const uint8_t *)[data bytes] maxLength:[data length]];
344
+ } else {
345
+ [respData appendData:data];
346
+ }
347
+
348
+ if (expectedBytes == 0) {
349
+ return;
350
+ }
351
+
352
+ // For non-chunked download, progress is received / expected
353
+ // For chunked download, progress can be either 0 (started) or 1 (ended)
354
+ NSNumber *now;
355
+ if (expectedBytes != NSURLResponseUnknownLength) {
356
+ now = [NSNumber numberWithFloat:((float)receivedBytes/(float)expectedBytes)];
357
+ } else {
358
+ now = @0;
359
+ }
360
+
361
+ if ([self.progressConfig shouldReport:now]) {
362
+ NSDictionary *body;
363
+ if (expectedBytes == NSURLResponseUnknownLength) {
364
+ // For chunked downloads
365
+ body = @{
366
+ @"taskId": taskId,
367
+ @"written": [NSString stringWithFormat:@"%d", 0],
368
+ @"total": [NSString stringWithFormat:@"%lld", (long long) expectedBytes],
369
+ @"chunk": chunkString,
370
+ };
371
+ } else {
372
+ // For non-chunked downloads
373
+ body = @{
374
+ @"taskId": taskId,
375
+ @"written": [NSString stringWithFormat:@"%lld", (long long) receivedBytes],
376
+ @"total": [NSString stringWithFormat:@"%lld", (long long) expectedBytes],
377
+ @"chunk": chunkString,
378
+ };
379
+ }
380
+ [self.baseModule emitEventDict:EVENT_PROGRESS body:body];
381
+ }
382
+ }
383
+
384
+ - (void) URLSession:(NSURLSession *)session didBecomeInvalidWithError:(nullable NSError *)error
385
+ {
386
+ if ([session isEqual:session]) {
387
+ session = nil;
388
+ }
389
+ }
390
+
391
+
392
+ - (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
393
+ {
394
+
395
+ self.error = error;
396
+ NSString * errMsg;
397
+ NSString * respStr;
398
+ NSString * rnfbRespType;
399
+
400
+ // only run this if we were requested to change it
401
+ if ([[options objectForKey:CONFIG_INDICATOR] boolValue]) {
402
+ dispatch_async(dispatch_get_main_queue(), ^{
403
+ [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
404
+ });
405
+ }
406
+
407
+ if (error) {
408
+ if (error.domain == NSURLErrorDomain && error.code == NSURLErrorCancelled) {
409
+ errMsg = @"task cancelled";
410
+ } else {
411
+ errMsg = [error localizedDescription];
412
+ }
413
+ } else if ([self.progressConfig shouldReport:@1] && expectedBytes == NSURLResponseUnknownLength) {
414
+ // For chunked downloads
415
+ [self.baseModule emitEventDict:EVENT_PROGRESS body:@{
416
+ @"taskId": taskId,
417
+ @"written": [NSString stringWithFormat:@"%lld", (long long) receivedBytes],
418
+ @"total": [NSString stringWithFormat:@"%lld", (long long) receivedBytes],
419
+ @"chunk": @"",
420
+ }];
421
+ }
422
+
423
+ if (respFile) {
424
+ if ([self ShouldTransformFile]) {
425
+ // At this point, we have the data that we deferred to write into a file. We can now
426
+ // perform the conversion and write the converted data into the file.
427
+ NSObject<FileTransformer>* fileTransformer = [ReactNativeBlobUtilFileTransformer getFileTransformer];
428
+ if (!fileTransformer) {
429
+ errMsg = @"Transform file specified but file transfomer not set";
430
+ } else {
431
+ @try{
432
+ NSData* transformedData = [fileTransformer onWriteFile:respData];
433
+ [writeStream write:(const uint8_t *)[transformedData bytes] maxLength:[transformedData length]];
434
+ } @catch(NSException * ex)
435
+ {
436
+ errMsg = [NSString stringWithFormat:@"Exception on File Transformer: '%@' ", [ex description]];
437
+ }
438
+ }
439
+ }
440
+ [writeStream close];
441
+ rnfbRespType = RESP_TYPE_PATH;
442
+ respStr = destPath;
443
+ } else { // base64 response
444
+ // #73 fix unicode data encoding issue :
445
+ // when response type is BASE64, we should first try to encode the response data to UTF8 format
446
+ // if it turns out not to be `nil` that means the response data contains valid UTF8 string,
447
+ // in order to properly encode the UTF8 string, use URL encoding before BASE64 encoding.
448
+ NSString * utf8 = [[NSString alloc] initWithData:respData encoding:NSUTF8StringEncoding];
449
+
450
+ if (responseFormat == BASE64) {
451
+ rnfbRespType = RESP_TYPE_BASE64;
452
+ respStr = [respData base64EncodedStringWithOptions:0];
453
+ } else if (responseFormat == UTF8) {
454
+ rnfbRespType = RESP_TYPE_UTF8;
455
+ respStr = utf8;
456
+ } else {
457
+ if (utf8) {
458
+ rnfbRespType = RESP_TYPE_UTF8;
459
+ respStr = utf8;
460
+ } else {
461
+ rnfbRespType = RESP_TYPE_BASE64;
462
+ respStr = [respData base64EncodedStringWithOptions:0];
463
+ }
464
+ }
465
+ }
466
+
467
+
468
+ callback(@[
469
+ errMsg ?: [NSNull null],
470
+ rnfbRespType ?: @"",
471
+ respStr ?: [NSNull null]
472
+ ]);
473
+
474
+ respData = nil;
475
+ receivedBytes = 0;
476
+ [session finishTasksAndInvalidate];
477
+
478
+ }
479
+
480
+ - (BOOL) ShouldTransformFile{
481
+ return [[options valueForKey:CONFIG_TRANSFORM_FILE] boolValue];
482
+ }
483
+
484
+ // upload progress handler
485
+ - (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didSendBodyData:(int64_t)bytesSent totalBytesSent:(int64_t)totalBytesWritten totalBytesExpectedToSend:(int64_t)totalBytesExpectedToWrite
486
+ {
487
+ if (totalBytesExpectedToWrite == 0) {
488
+ return;
489
+ }
490
+
491
+ NSNumber * now = [NSNumber numberWithFloat:((float)totalBytesWritten/(float)totalBytesExpectedToWrite)];
492
+
493
+ if ([self.uploadProgressConfig shouldReport:now]) {
494
+ [self.baseModule emitEventDict:EVENT_PROGRESS_UPLOAD
495
+ body:@{
496
+ @"taskId": taskId,
497
+ @"written": [NSString stringWithFormat:@"%ld", (long) totalBytesWritten],
498
+ @"total": [NSString stringWithFormat:@"%ld", (long) totalBytesExpectedToWrite]
499
+ }
500
+ ];
501
+ }
502
+ }
503
+
504
+
505
+ - (void) URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable credantial))completionHandler
506
+ {
507
+ if ([[options valueForKey:CONFIG_TRUSTY] boolValue]) {
508
+ completionHandler(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]);
509
+ } else {
510
+ completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]);
511
+ }
512
+ }
513
+
514
+
515
+ - (void) URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session
516
+ {
517
+ NSLog(@"sess done in background");
518
+ }
519
+
520
+ - (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task willPerformHTTPRedirection:(NSHTTPURLResponse *)response newRequest:(NSURLRequest *)request completionHandler:(void (^)(NSURLRequest * _Nullable))completionHandler
521
+ {
522
+
523
+ if (followRedirect) {
524
+ if (request.URL) {
525
+ [redirects addObject:[request.URL absoluteString]];
526
+ }
527
+
528
+ completionHandler(request);
529
+ } else {
530
+ completionHandler(nil);
531
+ }
532
+ }
533
+
534
+
535
+ @end