Browse Source

Merge branch '0.5.2'

Ben Hsieh 8 years ago
parent
commit
70fcb281c9

+ 5
- 19
src/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java View File

@@ -160,18 +160,10 @@ public class RNFetchBlob extends ReactContextBaseJavaModule {
160 160
         RNFetchBlobConfig config = new RNFetchBlobConfig(options);
161 161
 
162 162
         try {
163
-            Uri uri = Uri.parse(url);
164 163
             AsyncHttpClient req = new AsyncHttpClient();
165 164
 
166
-            // set params
167
-            RequestParams params = new RequestParams();
168 165
             AbstractHttpEntity entity = null;
169 166
 
170
-            // set params
171
-            for (String paramName : uri.getQueryParameterNames()) {
172
-                params.put(paramName, uri.getQueryParameter(paramName));
173
-            }
174
-
175 167
             // set headers
176 168
             ReadableMapKeySetIterator it = headers.keySetIterator();
177 169
             while (it.hasNextKey()) {
@@ -212,7 +204,7 @@ public class RNFetchBlob extends ReactContextBaseJavaModule {
212 204
             // send request
213 205
             switch(method.toLowerCase()) {
214 206
                 case "get" :
215
-                    req.get(url, params, handler);
207
+                    req.get(url, handler);
216 208
                     break;
217 209
                 case "post" :
218 210
                     req.post(this.getReactApplicationContext(), url, entity, "octet-stream", handler);
@@ -221,7 +213,7 @@ public class RNFetchBlob extends ReactContextBaseJavaModule {
221 213
                     req.put(this.getReactApplicationContext(), url, entity, "octet-stream",handler);
222 214
                     break;
223 215
                 case "delete" :
224
-                    req.delete(url, params, handler);
216
+                    req.delete(url, handler);
225 217
                     break;
226 218
             }
227 219
         } catch(Exception error) {
@@ -235,16 +227,10 @@ public class RNFetchBlob extends ReactContextBaseJavaModule {
235 227
 
236 228
         RNFetchBlobConfig config = new RNFetchBlobConfig(options);
237 229
         try {
238
-            Uri uri = Uri.parse(url);
230
+
239 231
             AsyncHttpClient req = new AsyncHttpClient();
240 232
 
241
-            // set params
242
-            RequestParams params = new RequestParams();
243 233
             HttpEntity entity = null;
244
-            // set params
245
-            for (String paramName : uri.getQueryParameterNames()) {
246
-                params.put(paramName, uri.getQueryParameter(paramName));
247
-            }
248 234
 
249 235
             // set headers
250 236
             if(headers != null) {
@@ -307,7 +293,7 @@ public class RNFetchBlob extends ReactContextBaseJavaModule {
307 293
             // send request
308 294
             switch(method.toLowerCase()) {
309 295
                 case "get" :
310
-                    req.get(url, params, handler);
296
+                    req.get(url, handler);
311 297
                     break;
312 298
                 case "post" :
313 299
                     req.post(this.getReactApplicationContext(), url, entity, "multipart/form-data; charset=utf8", handler);
@@ -316,7 +302,7 @@ public class RNFetchBlob extends ReactContextBaseJavaModule {
316 302
                     req.put(this.getReactApplicationContext(), url, entity, "multipart/form-data",handler);
317 303
                     break;
318 304
                 case "delete" :
319
-                    req.delete(url, params, handler);
305
+                    req.delete(url, handler);
320 306
                     break;
321 307
             }
322 308
         } catch(Exception error) {

+ 0
- 1
src/index.js View File

@@ -104,7 +104,6 @@ function fetch(...args:any):Promise {
104 104
   let options = this || {}
105 105
 
106 106
   let promise = new Promise((resolve, reject) => {
107
-
108 107
     let [method, url, headers, body] = [...args]
109 108
     let nativeMethodName = Array.isArray(body) ? 'fetchBlobForm' : 'fetchBlob'
110 109
 

+ 6
- 6
src/ios/RNFetchBlob.xcodeproj/project.pbxproj View File

@@ -9,7 +9,7 @@
9 9
 /* Begin PBXBuildFile section */
10 10
 		A158F4271D052E49006FFD38 /* RNFetchBlobFS.m in Sources */ = {isa = PBXBuildFile; fileRef = A158F4261D052E49006FFD38 /* RNFetchBlobFS.m */; };
11 11
 		A158F42D1D0535BB006FFD38 /* RNFetchBlobConst.m in Sources */ = {isa = PBXBuildFile; fileRef = A158F42C1D0535BB006FFD38 /* RNFetchBlobConst.m */; };
12
-		A158F4301D0539DB006FFD38 /* RNFetchBlobResp.m in Sources */ = {isa = PBXBuildFile; fileRef = A158F42F1D0539DB006FFD38 /* RNFetchBlobResp.m */; };
12
+		A158F4301D0539DB006FFD38 /* RNFetchBlobNetwork.m in Sources */ = {isa = PBXBuildFile; fileRef = A158F42F1D0539DB006FFD38 /* RNFetchBlobNetwork.m */; };
13 13
 		A15C30141CD25C330074CB35 /* RNFetchBlob.m in Sources */ = {isa = PBXBuildFile; fileRef = A15C30131CD25C330074CB35 /* RNFetchBlob.m */; };
14 14
 		A166D1AA1CE0647A00273590 /* RNFetchBlob.h in Sources */ = {isa = PBXBuildFile; fileRef = A15C30111CD25C330074CB35 /* RNFetchBlob.h */; };
15 15
 /* End PBXBuildFile section */
@@ -31,8 +31,8 @@
31 31
 		A158F4281D052E57006FFD38 /* RNFetchBlobFS.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNFetchBlobFS.h; sourceTree = "<group>"; };
32 32
 		A158F4291D0534A9006FFD38 /* RNFetchBlobConst.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNFetchBlobConst.h; sourceTree = "<group>"; };
33 33
 		A158F42C1D0535BB006FFD38 /* RNFetchBlobConst.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNFetchBlobConst.m; sourceTree = "<group>"; };
34
-		A158F42E1D0539CE006FFD38 /* RNFetchBlobResp.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNFetchBlobResp.h; sourceTree = "<group>"; };
35
-		A158F42F1D0539DB006FFD38 /* RNFetchBlobResp.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNFetchBlobResp.m; sourceTree = "<group>"; };
34
+		A158F42E1D0539CE006FFD38 /* RNFetchBlobNetwork.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNFetchBlobNetwork.h; sourceTree = "<group>"; };
35
+		A158F42F1D0539DB006FFD38 /* RNFetchBlobNetwork.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNFetchBlobNetwork.m; sourceTree = "<group>"; };
36 36
 		A15C300E1CD25C330074CB35 /* libRNFetchBlob.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRNFetchBlob.a; sourceTree = BUILT_PRODUCTS_DIR; };
37 37
 		A15C30111CD25C330074CB35 /* RNFetchBlob.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = RNFetchBlob.h; path = RNFetchBlob/RNFetchBlob.h; sourceTree = "<group>"; };
38 38
 		A15C30131CD25C330074CB35 /* RNFetchBlob.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = RNFetchBlob.m; path = RNFetchBlob/RNFetchBlob.m; sourceTree = "<group>"; };
@@ -59,8 +59,8 @@
59 59
 		A15C30051CD25C330074CB35 = {
60 60
 			isa = PBXGroup;
61 61
 			children = (
62
-				A158F42F1D0539DB006FFD38 /* RNFetchBlobResp.m */,
63
-				A158F42E1D0539CE006FFD38 /* RNFetchBlobResp.h */,
62
+				A158F42F1D0539DB006FFD38 /* RNFetchBlobNetwork.m */,
63
+				A158F42E1D0539CE006FFD38 /* RNFetchBlobNetwork.h */,
64 64
 				A158F42C1D0535BB006FFD38 /* RNFetchBlobConst.m */,
65 65
 				A158F4291D0534A9006FFD38 /* RNFetchBlobConst.h */,
66 66
 				A158F4281D052E57006FFD38 /* RNFetchBlobFS.h */,
@@ -139,7 +139,7 @@
139 139
 				A166D1AA1CE0647A00273590 /* RNFetchBlob.h in Sources */,
140 140
 				A158F42D1D0535BB006FFD38 /* RNFetchBlobConst.m in Sources */,
141 141
 				A158F4271D052E49006FFD38 /* RNFetchBlobFS.m in Sources */,
142
-				A158F4301D0539DB006FFD38 /* RNFetchBlobResp.m in Sources */,
142
+				A158F4301D0539DB006FFD38 /* RNFetchBlobNetwork.m in Sources */,
143 143
 				A15C30141CD25C330074CB35 /* RNFetchBlob.m in Sources */,
144 144
 			);
145 145
 			runOnlyForDeploymentPostprocessing = 0;

+ 17
- 13
src/ios/RNFetchBlob/RNFetchBlob.m View File

@@ -10,7 +10,7 @@
10 10
 #import "RCTBridge.h"
11 11
 #import "RCTEventDispatcher.h"
12 12
 #import "RNFetchBlobFS.h"
13
-#import "RNFetchBlobResp.h"
13
+#import "RNFetchBlobNetwork.h"
14 14
 #import "RNFetchBlobConst.h"
15 15
 
16 16
 
@@ -61,13 +61,13 @@ RCT_EXPORT_METHOD(fetchBlobForm:(NSDictionary *)options
61 61
                   form:(NSArray *)form
62 62
                   callback:(RCTResponseSenderBlock)callback)
63 63
 {
64
-    
64
+    NSString * encodedUrl = [url stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
65 65
     // send request
66 66
     NSMutableURLRequest *request = [[NSMutableURLRequest alloc]
67 67
                                     initWithURL:[NSURL
68
-                                                 URLWithString: url]];
68
+                                                 URLWithString: encodedUrl]];
69 69
     
70
-    NSMutableDictionary *mheaders = [[NSMutableDictionary alloc] initWithDictionary:[ FetchBlobUtils normalizeHeaders:headers]];
70
+    NSMutableDictionary *mheaders = [[NSMutableDictionary alloc] initWithDictionary:[ RNFetchBlobNetwork normalizeHeaders:headers]];
71 71
     
72 72
     
73 73
     NSTimeInterval timeStamp = [[NSDate date] timeIntervalSince1970];
@@ -76,9 +76,9 @@ RCT_EXPORT_METHOD(fetchBlobForm:(NSDictionary *)options
76 76
     // generate boundary
77 77
     NSString * boundary = [NSString stringWithFormat:@"RNFetchBlob%d", timeStampObj];
78 78
     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
79
+        NSMutableData * postData = [[NSMutableData alloc] init];
79 80
         // if method is POST or PUT, convert data string format
80 81
         if([[method lowercaseString] isEqualToString:@"post"] || [[method lowercaseString] isEqualToString:@"put"]) {
81
-            NSMutableData * postData = [[NSMutableData alloc] init];
82 82
             
83 83
             // combine multipart/form-data body
84 84
             for(id field in form) {
@@ -128,7 +128,7 @@ RCT_EXPORT_METHOD(fetchBlobForm:(NSDictionary *)options
128 128
         
129 129
         
130 130
         // send HTTP request
131
-        FetchBlobUtils * utils = [[FetchBlobUtils alloc] init];
131
+        RNFetchBlobNetwork * utils = [[RNFetchBlobNetwork alloc] init];
132 132
         [utils sendRequest:options bridge:self.bridge taskId:taskId withRequest:request callback:callback];
133 133
     });
134 134
 }
@@ -141,29 +141,33 @@ RCT_EXPORT_METHOD(fetchBlob:(NSDictionary *)options
141 141
                   headers:(NSDictionary *)headers
142 142
                   body:(NSString *)body callback:(RCTResponseSenderBlock)callback)
143 143
 {
144
+    NSString * encodedUrl = [url stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
144 145
     // send request
145 146
     NSMutableURLRequest *request = [[NSMutableURLRequest alloc]
146 147
                                     initWithURL:[NSURL
147
-                                                 URLWithString: url]];
148
+                                                 URLWithString: encodedUrl]];
148 149
     
149
-    NSMutableDictionary *mheaders = [[NSMutableDictionary alloc] initWithDictionary:[FetchBlobUtils normalizeHeaders:headers]];
150
+    NSMutableDictionary *mheaders = [[NSMutableDictionary alloc] initWithDictionary:[RNFetchBlobNetwork normalizeHeaders:headers]];
150 151
     // move heavy task to another thread
151 152
     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
153
+        NSMutableData * blobData;
152 154
         // if method is POST or PUT, convert data string format
153 155
         if([[method lowercaseString] isEqualToString:@"post"] || [[method lowercaseString] isEqualToString:@"put"]) {
154 156
             // generate octet-stream body
155 157
             if(body != nil) {
156
-                NSMutableData * blobData;
157 158
                 
158 159
                 // when body is a string contains file path prefix, try load file from the path
159 160
                 if([body hasPrefix:self.filePathPrefix]) {
160 161
                     NSString * orgPath = [body substringFromIndex:[self.filePathPrefix length]];
161
-                    blobData = [[NSData alloc] initWithContentsOfFile:orgPath];
162
+                    [request setHTTPBodyStream: [NSInputStream inputStreamWithFileAtPath:orgPath ]];
163
+//                    blobData = [[NSData alloc] initWithContentsOfFile:orgPath];
162 164
                 }
163 165
                 // otherwise convert it as BASE64 data string
164
-                else
166
+                else {
165 167
                     blobData = [[NSData alloc] initWithBase64EncodedString:body options:0];
166
-                [request setHTTPBody:blobData];
168
+                    [request setHTTPBody:blobData];
169
+                }
170
+                
167 171
                 [mheaders setValue:@"application/octet-stream" forKey:@"content-type"];
168 172
                 
169 173
             }
@@ -173,7 +177,7 @@ RCT_EXPORT_METHOD(fetchBlob:(NSDictionary *)options
173 177
         [request setAllHTTPHeaderFields:mheaders];
174 178
         
175 179
         // send HTTP request
176
-        FetchBlobUtils * utils = [[FetchBlobUtils alloc] init];
180
+        RNFetchBlobNetwork * utils = [[RNFetchBlobNetwork alloc] init];
177 181
         [utils sendRequest:options bridge:self.bridge taskId:taskId withRequest:request callback:callback];
178 182
     });
179 183
 }

src/ios/RNFetchBlobResp.h → src/ios/RNFetchBlobNetwork.h View File

@@ -1,9 +1,9 @@
1 1
 //
2
-//  RNFetchBlobResp.h
2
+//  RNFetchBlobNetwork.h
3 3
 //  RNFetchBlob
4 4
 //
5
-//  Created by Ben Hsieh on 2016/6/6.
6
-//  Copyright © 2016年 suzuri04x2. All rights reserved.
5
+//  Created by wkh237 on 2016/6/6.
6
+//  Copyright © 2016 wkh237. All rights reserved.
7 7
 //
8 8
 
9 9
 #ifndef RNFetchBlobResp_h
@@ -12,7 +12,7 @@
12 12
 #import <Foundation/Foundation.h>
13 13
 #import "RCTBridgeModule.h"
14 14
 
15
-@interface FetchBlobUtils : NSObject  <NSURLConnectionDelegate, NSURLConnectionDataDelegate> {
15
+@interface RNFetchBlobNetwork : NSObject  <NSURLSessionDelegate, NSURLSessionTaskDelegate, NSURLSessionDataDelegate> {
16 16
     
17 17
     NSString * taskId;
18 18
     int expectedBytes;

+ 180
- 0
src/ios/RNFetchBlobNetwork.m View File

@@ -0,0 +1,180 @@
1
+//
2
+//  RNFetchBlobNetwork.m
3
+//  RNFetchBlob
4
+//
5
+//  Created by wkh237 on 2016/6/6.
6
+//  Copyright © 2016 wkh237. All rights reserved.
7
+//
8
+
9
+#import "RCTConvert.h"
10
+#import "RCTLog.h"
11
+#import <Foundation/Foundation.h>
12
+#import "RCTBridge.h"
13
+#import "RCTEventDispatcher.h"
14
+#import "RNFetchBlobFS.h"
15
+#import "RNFetchBlobNetwork.h"
16
+#import "RNFetchBlobConst.h"
17
+
18
+////////////////////////////////////////
19
+//
20
+//  HTTP request handler
21
+//
22
+////////////////////////////////////////
23
+
24
+@implementation RNFetchBlobNetwork
25
+
26
+
27
+@synthesize taskId;
28
+@synthesize expectedBytes;
29
+@synthesize receivedBytes;
30
+@synthesize respData;
31
+@synthesize callback;
32
+@synthesize bridge;
33
+@synthesize options;
34
+
35
+// constructor
36
+- (id)init {
37
+    self = [super init];
38
+    return self;
39
+}
40
+
41
+
42
+// removing case from headers
43
++ (NSMutableDictionary *) normalizeHeaders:(NSDictionary *)headers {
44
+    
45
+    NSMutableDictionary * mheaders = [[NSMutableDictionary alloc]init];
46
+    for(NSString * key in headers) {
47
+        [mheaders setValue:[headers valueForKey:key] forKey:[key lowercaseString]];
48
+    }
49
+    
50
+    return mheaders;
51
+}
52
+
53
+// send HTTP request
54
+- (void) sendRequest:(NSDictionary *)options bridge:(RCTBridge *)bridgeRef taskId:(NSString *)taskId withRequest:(NSURLRequest *)req callback:(RCTResponseSenderBlock) callback {
55
+    self.taskId = taskId;
56
+    self.respData = [[NSMutableData alloc] initWithLength:0];
57
+    self.callback = callback;
58
+    self.bridge = bridgeRef;
59
+    self.expectedBytes = 0;
60
+    self.receivedBytes = 0;
61
+    self.options = options;
62
+    
63
+    NSString * path = [self.options valueForKey:CONFIG_FILE_PATH];
64
+    NSString * ext = [self.options valueForKey:CONFIG_FILE_EXT];
65
+
66
+    NSURLSession * session = [NSURLSession sharedSession];
67
+    
68
+    // file will be stored at a specific path
69
+    if( path != nil) {
70
+        NSURLSessionDownloadTask * task = [session downloadTaskWithRequest:req completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {
71
+            if(error != nil) {
72
+                callback(@[[error localizedDescription]]);
73
+                return;
74
+            }
75
+            NSError * taskErr;
76
+            NSFileManager * fm = [NSFileManager defaultManager];
77
+            // move temp file to desination
78
+            [fm moveItemAtURL:location toURL:[NSURL fileURLWithPath:path] error:&taskErr];
79
+            if(taskErr != nil) {
80
+                callback(@[[taskErr localizedDescription]]);
81
+                return;
82
+            }
83
+            callback(@[[NSNull null], path]);
84
+        }];
85
+        [task resume];
86
+    }
87
+    // file will be stored at tmp path
88
+    else if ( [self.options valueForKey:CONFIG_USE_TEMP]!= nil ) {
89
+        NSURLSessionDownloadTask * task = [session downloadTaskWithRequest:req completionHandler:^(NSURL * _Nullable location, NSURLResponse * _Nullable response, NSError * _Nullable error) {
90
+            if(error != nil) {
91
+                callback(@[[error localizedDescription]]);
92
+                return;
93
+            }
94
+            NSError * taskErr;
95
+            NSFileManager * fm = [NSFileManager defaultManager];
96
+            NSString * tmpPath = [RNFetchBlobFS getTempPath:self.taskId withExtension:[self.options valueForKey:CONFIG_FILE_EXT]];
97
+            // move temp file to desination
98
+            [fm moveItemAtURL:location toURL:[NSURL fileURLWithPath:tmpPath] error:&taskErr];
99
+            if(taskErr != nil) {
100
+                callback(@[[taskErr localizedDescription]]);
101
+                return;
102
+            }
103
+            callback(@[[NSNull null], tmpPath]);
104
+        }];
105
+        [task resume];
106
+    }
107
+    // base64 response
108
+    else {
109
+        NSURLSessionUploadTask * task =
110
+        
111
+        [session dataTaskWithRequest:req completionHandler:^(NSData * _Nullable resp, NSURLResponse * _Nullable response, NSError * _Nullable error) {
112
+            if(error != nil) {
113
+                callback(@[[error localizedDescription]]);
114
+                return;
115
+            }
116
+            else {
117
+                callback(@[[NSNull null], [resp base64EncodedStringWithOptions:0]]);
118
+            }
119
+        }];
120
+        [task resume];
121
+    }
122
+}
123
+
124
+////////////////////////////////////////
125
+//
126
+//  NSURLSession delegates
127
+//
128
+////////////////////////////////////////
129
+
130
+
131
+#pragma mark NSURLSession delegate methods
132
+
133
+// set expected content length on response received
134
+- (void) URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler
135
+{
136
+    expectedBytes = [response expectedContentLength];
137
+}
138
+
139
+// download progress handler
140
+- (void) URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data
141
+{
142
+    receivedBytes += [data length];
143
+    
144
+    Boolean fileCache = [self.options valueForKey:CONFIG_USE_TEMP];
145
+    NSString * path = [self.options valueForKey:CONFIG_FILE_PATH];
146
+    // cache data in memory
147
+    if(path == nil && fileCache == nil) {
148
+        [respData appendData:data];
149
+    }
150
+    
151
+    [self.bridge.eventDispatcher
152
+     sendDeviceEventWithName:@"RNFetchBlobProgress"
153
+     body:@{
154
+            @"taskId": taskId,
155
+            @"written": [NSString stringWithFormat:@"%d", receivedBytes],
156
+            @"total": [NSString stringWithFormat:@"%d", expectedBytes]
157
+            }
158
+     ];
159
+}
160
+
161
+- (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
162
+    NSLog([error localizedDescription]);
163
+}
164
+
165
+// upload progress handler
166
+- (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didSendBodyData:(int64_t)bytesSent totalBytesSent:(int64_t)totalBytesWritten totalBytesExpectedToSend:(int64_t)totalBytesExpectedToWrite
167
+{
168
+    expectedBytes = totalBytesExpectedToWrite;
169
+    receivedBytes += totalBytesWritten;
170
+    [self.bridge.eventDispatcher
171
+     sendDeviceEventWithName:@"RNFetchBlobProgress"
172
+     body:@{
173
+            @"taskId": taskId,
174
+            @"written": [NSString stringWithFormat:@"%d", receivedBytes],
175
+            @"total": [NSString stringWithFormat:@"%d", expectedBytes]
176
+            }
177
+     ];
178
+}
179
+
180
+@end

+ 0
- 188
src/ios/RNFetchBlobResp.m View File

@@ -1,188 +0,0 @@
1
-//
2
-//  RNFetchBlobResp.m
3
-//  RNFetchBlob
4
-//
5
-//  Created by Ben Hsieh on 2016/6/6.
6
-//  Copyright © 2016年 suzuri04x2. All rights reserved.
7
-//
8
-
9
-#import "RCTConvert.h"
10
-#import "RCTLog.h"
11
-#import <Foundation/Foundation.h>
12
-#import "RCTBridge.h"
13
-#import "RCTEventDispatcher.h"
14
-#import "RNFetchBlobFS.h"
15
-#import "RNFetchBlobResp.h"
16
-#import "RNFetchBlobConst.h"
17
-
18
-////////////////////////////////////////
19
-//
20
-//  HTTP request handler
21
-//
22
-////////////////////////////////////////
23
-
24
-@implementation FetchBlobUtils
25
-
26
-
27
-@synthesize taskId;
28
-@synthesize expectedBytes;
29
-@synthesize receivedBytes;
30
-@synthesize respData;
31
-@synthesize callback;
32
-@synthesize bridge;
33
-@synthesize options;
34
-
35
-
36
-// removing case from headers
37
-+ (NSMutableDictionary *) normalizeHeaders:(NSDictionary *)headers {
38
-    
39
-    NSMutableDictionary * mheaders = [[NSMutableDictionary alloc]init];
40
-    for(NSString * key in headers) {
41
-        [mheaders setValue:[headers valueForKey:key] forKey:[key lowercaseString]];
42
-    }
43
-    
44
-    return mheaders;
45
-}
46
-
47
-- (id)init {
48
-    self = [super init];
49
-    return self;
50
-}
51
-
52
-
53
-- (void) sendRequest:(NSDictionary *)options bridge:(RCTBridge *)bridgeRef taskId:(NSString *)taskId withRequest:(NSURLRequest *)req callback:(RCTResponseSenderBlock) callback {
54
-    self.taskId = taskId;
55
-    self.respData = [[NSMutableData alloc] initWithLength:0];
56
-    self.callback = callback;
57
-    self.bridge = bridgeRef;
58
-    self.expectedBytes = 0;
59
-    self.receivedBytes = 0;
60
-    self.options = options;
61
-    
62
-    NSString * path = [self.options valueForKey:CONFIG_FILE_PATH];
63
-    NSString * ext = [self.options valueForKey:CONFIG_FILE_EXT];
64
-    
65
-    // open file stream for write
66
-    if( path != nil) {
67
-        self.fileStream = [[RNFetchBlobFS alloc]initWithCallback:self.callback];
68
-        [self.fileStream openWithPath:path encode:@"ascii" appendData:YES ];
69
-    }
70
-    else if ( [self.options valueForKey:CONFIG_USE_TEMP]!= nil ) {
71
-        self.fileStream = [[RNFetchBlobFS alloc]initWithCallback:self.callback];
72
-        [self.fileStream openWithPath:[RNFetchBlobFS getTempPath:taskId withExtension:ext] encode:@"ascii" appendData:YES];
73
-    }
74
-    
75
-    NSURLConnection *conn = [[NSURLConnection alloc] initWithRequest:req delegate:self startImmediately:NO];
76
-    [conn scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
77
-    [conn start];
78
-    
79
-    if(!conn) {
80
-        callback(@[[NSString stringWithFormat:@"RNFetchBlob could not initialize connection"], [NSNull null]]);
81
-    }
82
-}
83
-
84
-
85
-#pragma mark NSURLConnection delegate methods
86
-
87
-
88
-- (void) connection:(NSURLConnection *)connection didReceiveResponse:(nonnull NSURLResponse *)response {
89
-    //    [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
90
-    expectedBytes = [response expectedContentLength];
91
-}
92
-
93
-
94
-- (void) connection:(NSURLConnection *)connection didReceiveData:(nonnull NSData *)data {
95
-    receivedBytes += [data length];
96
-    
97
-    Boolean fileCache = [self.options valueForKey:CONFIG_USE_TEMP];
98
-    NSString * path = [self.options valueForKey:CONFIG_FILE_PATH];
99
-    if(path != nil) {
100
-        
101
-        [self.fileStream write:data];
102
-    }
103
-    // write to tmp file
104
-    else if( fileCache != nil) {
105
-        NSString * ext = [self.options valueForKey:CONFIG_FILE_EXT];
106
-        [self.fileStream write:data];
107
-    }
108
-    // cache data in memory
109
-    else {
110
-        [respData appendData:data];
111
-    }
112
-    
113
-    [self.bridge.eventDispatcher
114
-     sendDeviceEventWithName:@"RNFetchBlobProgress"
115
-     body:@{
116
-            @"taskId": taskId,
117
-            @"written": [NSString stringWithFormat:@"%d", receivedBytes],
118
-            @"total": [NSString stringWithFormat:@"%d", expectedBytes]
119
-            }
120
-     ];
121
-}
122
-
123
-- (void) connection:(NSURLConnection *)connection didSendBodyData:(NSInteger)bytesWritten totalBytesWritten:(NSInteger)totalBytesWritten totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite {
124
-    
125
-    expectedBytes = totalBytesExpectedToWrite;
126
-    receivedBytes += totalBytesWritten;
127
-    [self.bridge.eventDispatcher
128
-     sendDeviceEventWithName:@"RNFetchBlobProgress"
129
-     body:@{
130
-            @"taskId": taskId,
131
-            @"written": [NSString stringWithFormat:@"%d", receivedBytes],
132
-            @"total": [NSString stringWithFormat:@"%d", expectedBytes]
133
-            }
134
-     ];
135
-    
136
-}
137
-
138
-- (void) connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
139
-    
140
-    //    [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
141
-    
142
-    [self.fileStream closeInStream];
143
-    [self.fileStream closeOutStream];
144
-    
145
-    callback(@[[error localizedDescription], [NSNull null]]);
146
-}
147
-
148
-- (NSCachedURLResponse *) connection:(NSURLConnection *)connection willCacheResponse: (NSCachedURLResponse *)cachedResponse {
149
-    return nil;
150
-}
151
-
152
-
153
-// handle 301 and 302 responses
154
-- (NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:response {
155
-    return request;
156
-}
157
-
158
-// request complete
159
-- (void) connectionDidFinishLoading:(NSURLConnection *)connection {
160
-    
161
-    NSData * data;
162
-    if(respData != nil)
163
-        data = [NSData dataWithData:respData];
164
-    else
165
-        data = [[NSData alloc] init];
166
-    
167
-    NSString * path = [self.options valueForKey:CONFIG_FILE_PATH];
168
-    NSString * ext = [self.options valueForKey:CONFIG_FILE_EXT];
169
-    Boolean useCache = [self.options valueForKey:CONFIG_USE_TEMP];
170
-    
171
-    [self.fileStream closeInStream];
172
-    
173
-    // if fileCache is true or file path is given, return a path
174
-    if( path != nil ) {
175
-        callback(@[[NSNull null], path]);
176
-    }
177
-    // when fileCache option is set but no path specified, save to tmp path
178
-    else if( [self.options valueForKey:CONFIG_USE_TEMP] != nil) {
179
-        NSString * tmpPath = [RNFetchBlobFS getTempPath:taskId withExtension:ext];
180
-        callback(@[[NSNull null], tmpPath]);
181
-    }
182
-    // otherwise return base64 string
183
-    else {
184
-        callback(@[[NSNull null], [data base64EncodedStringWithOptions:0]]);
185
-    }
186
-}
187
-
188
-@end

+ 1
- 1
src/package.json View File

@@ -1,6 +1,6 @@
1 1
 {
2 2
   "name": "react-native-fetch-blob",
3
-  "version": "0.5.1",
3
+  "version": "0.5.2",
4 4
   "description": "A module provides upload, download, and files access API. Supports file stream read/write for process large files.",
5 5
   "main": "index.js",
6 6
   "scripts": {

+ 11
- 11
test-server/server.js View File

@@ -41,19 +41,19 @@ app.use('/public', express.static('./public'))
41 41
 app.get('/redirect', function(req, res) {
42 42
   res.redirect('/public/github.png')
43 43
 })
44
-// handle octet-stream request
45
-app.post('/upload', function(req, res){
46
-
47
-  console.log(req.headers)
48
-  console.log(req.body)
49
-  fs.writeFile('./uploads/file'+Date.now()+'.png', req.body,function(err){
50
-    if(!err)
51
-      res.status(200).send({ message : 'ok'})
52
-    else
53
-      res.status(500).send({ message : err})
54
-  })
55 44
 
45
+app.all('/params', function(req, res) {
46
+  console.log(req.url)
47
+    var resp =
48
+      {
49
+         time : req.query.time,
50
+         name : req.query.name,
51
+         lang : req.query.lang
52
+      }
53
+    console.log(resp)
54
+    res.send(resp)
56 55
 })
56
+
57 57
 // return an empty response
58 58
 app.all('/empty', function(req, res) {
59 59
   res.send('')

test/test-0.5.x.js → test/test-0.5.1.js View File

@@ -15,7 +15,7 @@ import {
15 15
 const fs = RNFetchBlob.fs
16 16
 const { Assert, Comparer, Info, prop } = RNTest
17 17
 const describe = RNTest.config({
18
-  group : '0.5.x',
18
+  group : '0.5.1',
19 19
   run : true,
20 20
   expand : false,
21 21
 })
@@ -35,6 +35,7 @@ describe('Download file to storage with custom file extension', (report, done) =
35 35
     })
36 36
     .fetch('GET', `${TEST_SERVER_URL}/public/github2.jpg`)
37 37
     .then((resp) => {
38
+      console.log(resp.path())
38 39
       tmpFilePath = resp.path()
39 40
       report(<Info key={`image from ${tmpFilePath}`}>
40 41
         <Image
@@ -145,6 +146,69 @@ describe('Upload multipart data with file from storage', (report, done) => {
145 146
     })
146 147
 })
147 148
 
149
+describe('Upload and download at the same time', (report, done) => {
150
+
151
+  let content = 'POST and PUT calls with headers and body should also work correctly'
152
+  let filename = 'download-header-test-' + Date.now()
153
+  let body = RNFetchBlob.base64.encode(content)
154
+
155
+  RNFetchBlob
156
+    .config({
157
+      fileCache : true,
158
+    })
159
+    .fetch('POST', 'https://content.dropboxapi.com/2/files/upload', {
160
+      Authorization : `Bearer ${DROPBOX_TOKEN}`,
161
+      'Dropbox-API-Arg': '{\"path\": \"/rn-upload/'+filename+'\",\"mode\": \"add\",\"autorename\": true,\"mute\": false}',
162
+      'Content-Type' : 'application/octet-stream',
163
+    }, body)
164
+    .then((resp) =>  {
165
+      return RNFetchBlob.fs.readStream(resp.path(), 'utf8')
166
+    })
167
+    .then((stream) => {
168
+      let actual = ''
169
+      stream.open()
170
+      stream.onData((chunk) => {
171
+        actual += chunk
172
+      })
173
+      stream.onEnd(() => {
174
+        report(
175
+          <Assert
176
+            key="response data should be the filename"
177
+            expect={filename}
178
+            actual={JSON.parse(actual).name} />)
179
+        done()
180
+      })
181
+    })
182
+
183
+})
184
+
185
+RNTest.config({
186
+  group : '0.5.1',
187
+  run : true,
188
+  expand : false,
189
+  timeout : 30000,
190
+})('Upload and download large file', (report, done) => {
191
+  let filename = '22mb-dummy-' + Date.now()
192
+  RNFetchBlob.config({
193
+    fileCache : true
194
+  })
195
+  .fetch('GET', `${TEST_SERVER_URL}/public/22mb-dummy`)
196
+  .then((res) => {
197
+    return RNFetchBlob.fetch('POST', 'https://content.dropboxapi.com/2/files/upload', {
198
+      Authorization : `Bearer ${DROPBOX_TOKEN}`,
199
+      'Dropbox-API-Arg': '{\"path\": \"/rn-upload/'+filename+'\",\"mode\": \"add\",\"autorename\": true,\"mute\": false}',
200
+      'Content-Type' : 'application/octet-stream',
201
+    }, RNFetchBlob.wrap(res.path()))
202
+  })
203
+  .then((res) => {
204
+    report(<Assert
205
+      key="upload should success withou crashing app"
206
+      expect={filename}
207
+      actual={res.json().name}/>)
208
+    done()
209
+  })
210
+})
211
+
148 212
 describe('Session create mechanism test', (report, done) => {
149 213
   let sessionName = 'foo-' + Date.now()
150 214
   testSessionName = sessionName
@@ -158,7 +222,7 @@ describe('Session create mechanism test', (report, done) => {
158 222
     })
159 223
     .fetch('GET', `${TEST_SERVER_URL}/public/github.png`)
160 224
   let p3 = RNFetchBlob.config({
161
-      path : sysDirs.DocumentDir + '/session-test.png'
225
+      path : sysDirs.DocumentDir + '/session-test'+Date.now()+'.png'
162 226
     })
163 227
     .fetch('GET', `${TEST_SERVER_URL}/public/github.png`)
164 228
 

+ 86
- 0
test/test-0.5.2.js View File

@@ -0,0 +1,86 @@
1
+import RNTest from './react-native-testkit/'
2
+import React from 'react'
3
+import RNFetchBlob from 'react-native-fetch-blob'
4
+
5
+import {
6
+  StyleSheet,
7
+  Text,
8
+  View,
9
+  ScrollView,
10
+  Platform,
11
+  Dimensions,
12
+  Image,
13
+} from 'react-native';
14
+
15
+const fs = RNFetchBlob.fs
16
+const { Assert, Comparer, Info, prop } = RNTest
17
+const describe = RNTest.config({
18
+  group : '0.5.2',
19
+  run : true,
20
+  expand : false,
21
+})
22
+const { TEST_SERVER_URL, FILENAME, DROPBOX_TOKEN, styles } = prop()
23
+
24
+let prefix = ((Platform.OS === 'android') ? 'file://' : '')
25
+
26
+
27
+describe('GET request with params', (report, done) => {
28
+  let time = Date.now()
29
+  RNFetchBlob.config({ fileCache : true })
30
+    .fetch('GET', `${TEST_SERVER_URL}/params?time=${time}&name=RNFetchBlobParams&lang=中文`)
31
+    .then((resp) => {
32
+      let file = resp.path()
33
+      return RNFetchBlob.fs.readStream(resp.path(), 'utf8')
34
+    })
35
+    .then((stream) => {
36
+      let result = ''
37
+      stream.open()
38
+      stream.onData((chunk) => {
39
+        result += chunk
40
+      })
41
+      stream.onEnd(() => {
42
+        result = JSON.parse(result)
43
+        report(<Assert key="param#1 should correct"
44
+          expect={parseInt(time)}
45
+          actual={parseInt(result.time)}/>,
46
+        <Assert key="param#2 should correct"
47
+          expect={'RNFetchBlobParams'}
48
+          actual={result.name}/>,
49
+        <Assert key="param contains unicode data should correct"
50
+          expect={'中文'}
51
+          actual={result.lang}/>)
52
+          done()
53
+      })
54
+    })
55
+})
56
+
57
+
58
+describe('POST request with params', (report, done) => {
59
+  let time = Date.now()
60
+  RNFetchBlob.config({ fileCache : true })
61
+    .fetch('POST', `${TEST_SERVER_URL}/params?time=${time}&name=RNFetchBlobParams&lang=中文`)
62
+    .then((resp) => {
63
+      let file = resp.path()
64
+      return RNFetchBlob.fs.readStream(resp.path(), 'utf8')
65
+    })
66
+    .then((stream) => {
67
+      let result = ''
68
+      stream.open()
69
+      stream.onData((chunk) => {
70
+        result += chunk
71
+      })
72
+      stream.onEnd(() => {
73
+        result = JSON.parse(result)
74
+        report(<Assert key="param#1 should correct"
75
+          expect={parseInt(time)}
76
+          actual={parseInt(result.time)}/>,
77
+        <Assert key="param#2 should correct"
78
+          expect={'RNFetchBlobParams'}
79
+          actual={result.name}/>,
80
+        <Assert key="param contains unicode data should correct"
81
+          expect={'中文'}
82
+          actual={result.lang}/>)
83
+          done()
84
+      })
85
+    })
86
+})

+ 4
- 5
test/test-init.js View File

@@ -18,7 +18,7 @@ const { Assert, Comparer, Info, describe, prop } = RNTest
18 18
 // test environment variables
19 19
 
20 20
 prop('FILENAME', `${Platform.OS}-0.5.0-${Date.now()}.png`)
21
-prop('TEST_SERVER_URL', 'http://192.168.16.70:8123')
21
+prop('TEST_SERVER_URL', 'http://localhost:8123')
22 22
 prop('DROPBOX_TOKEN', 'fsXcpmKPrHgAAAAAAAAAoXZhcXYWdgLpQMan6Tb_bzJ237DXhgQSev12hA-gUXt4')
23 23
 prop('styles', {
24 24
   image : {
@@ -39,7 +39,6 @@ describe('GET image from server', (report, done) => {
39 39
       Authorization : 'Bearer abde123eqweje'
40 40
     })
41 41
     .then((resp) => {
42
-
43 42
       RNTest.prop('image', resp.base64())
44 43
       report(
45 44
         <Info key="Response image">
@@ -51,8 +50,8 @@ describe('GET image from server', (report, done) => {
51 50
     })
52 51
 })
53 52
 
54
-
55
-require('./test-fs')
56 53
 require('./test-0.1.x-0.4.x')
57
-require('./test-0.5.x')
54
+require('./test-0.5.1')
55
+require('./test-0.5.2')
56
+require('./test-fs')
58 57
 require('./test-android')