Browse Source

Add cookie related implementation #156

Ben Hsieh 7 years ago
parent
commit
6a435dab60

+ 16
- 0
src/android/src/main/java/com/RNFetchBlob/RNFetchBlob.java View File

@@ -3,6 +3,7 @@ package com.RNFetchBlob;
3 3
 import android.content.Intent;
4 4
 import android.net.Uri;
5 5
 
6
+import com.RNFetchBlob.Utils.RNFBCookieJar;
6 7
 import com.facebook.react.bridge.Callback;
7 8
 import com.facebook.react.bridge.Promise;
8 9
 import com.facebook.react.bridge.ReactApplicationContext;
@@ -10,6 +11,7 @@ import com.facebook.react.bridge.ReactContextBaseJavaModule;
10 11
 import com.facebook.react.bridge.ReactMethod;
11 12
 import com.facebook.react.bridge.ReadableArray;
12 13
 import com.facebook.react.bridge.ReadableMap;
14
+import com.facebook.react.bridge.WritableArray;
13 15
 
14 16
 import java.util.Map;
15 17
 import java.util.concurrent.LinkedBlockingQueue;
@@ -203,6 +205,20 @@ public class RNFetchBlob extends ReactContextBaseJavaModule {
203 205
 
204 206
     }
205 207
 
208
+    @ReactMethod
209
+    /**
210
+     * Get cookies belongs specific host.
211
+     * @param host String host name.
212
+     */
213
+    public void getCookies(String host, Promise promise) {
214
+        try {
215
+            WritableArray cookies = RNFBCookieJar.getCookies(host);
216
+            promise.resolve(cookies);
217
+        } catch(Exception err) {
218
+            promise.reject("RNFetchBlob.getCookies", err.getMessage());
219
+        }
220
+    }
221
+
206 222
     @ReactMethod
207 223
     /**
208 224
      * @param path Stream file path

+ 9
- 0
src/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java View File

@@ -11,6 +11,7 @@ import android.util.Base64;
11 11
 
12 12
 import com.RNFetchBlob.Response.RNFetchBlobDefaultResp;
13 13
 import com.RNFetchBlob.Response.RNFetchBlobFileResp;
14
+import com.RNFetchBlob.Utils.RNFBCookieJar;
14 15
 import com.facebook.react.bridge.Arguments;
15 16
 import com.facebook.react.bridge.Callback;
16 17
 import com.facebook.react.bridge.ReactApplicationContext;
@@ -25,6 +26,9 @@ import java.io.File;
25 26
 import java.io.FileOutputStream;
26 27
 import java.io.IOException;
27 28
 import java.io.InputStream;
29
+import java.net.CookieHandler;
30
+import java.net.CookieManager;
31
+import java.net.CookiePolicy;
28 32
 import java.net.MalformedURLException;
29 33
 import java.net.SocketException;
30 34
 import java.net.SocketTimeoutException;
@@ -39,6 +43,7 @@ import java.util.concurrent.TimeUnit;
39 43
 
40 44
 import okhttp3.Call;
41 45
 import okhttp3.ConnectionPool;
46
+import okhttp3.CookieJar;
42 47
 import okhttp3.Headers;
43 48
 import okhttp3.Interceptor;
44 49
 import okhttp3.MediaType;
@@ -290,7 +295,11 @@ public class RNFetchBlobReq extends BroadcastReceiver implements Runnable {
290 295
                     break;
291 296
             }
292 297
 
298
+            // #156 fix cookie issue
299
+
300
+
293 301
             final Request req = builder.build();
302
+            clientBuilder.cookieJar(new RNFBCookieJar());
294 303
             clientBuilder.addNetworkInterceptor(new Interceptor() {
295 304
                 @Override
296 305
                 public Response intercept(Chain chain) throws IOException {

+ 53
- 0
src/android/src/main/java/com/RNFetchBlob/Utils/RNFBCookieJar.java View File

@@ -0,0 +1,53 @@
1
+package com.RNFetchBlob.Utils;
2
+
3
+import com.facebook.react.bridge.Arguments;
4
+import com.facebook.react.bridge.ReadableMap;
5
+import com.facebook.react.bridge.WritableArray;
6
+import com.facebook.react.bridge.WritableMap;
7
+
8
+import java.util.ArrayList;
9
+import java.util.HashMap;
10
+import java.util.List;
11
+
12
+import okhttp3.Cookie;
13
+import okhttp3.CookieJar;
14
+import okhttp3.HttpUrl;
15
+
16
+/**
17
+ * Created by wkh237on 2016/10/14.
18
+ */
19
+
20
+
21
+
22
+public class RNFBCookieJar implements CookieJar {
23
+
24
+    static final HashMap<String, List<Cookie>> cookieStore = new HashMap<>();
25
+    private List<Cookie> cookies;
26
+
27
+    @Override
28
+    public void saveFromResponse(HttpUrl url, List<Cookie> cookies) {
29
+        cookieStore.put(url.host(), cookies);
30
+    }
31
+
32
+    @Override
33
+    public List<Cookie> loadForRequest(HttpUrl url) {
34
+        List<Cookie> cookies = cookieStore.get(url.host());
35
+        return cookies != null ? cookies : new ArrayList<Cookie>();
36
+    }
37
+
38
+    public static WritableArray getCookies(String host) {
39
+        HttpUrl url = HttpUrl.parse(host);
40
+        List<Cookie> cookies = null;
41
+        if(url != null) {
42
+            cookies = cookieStore.get(url.host());
43
+        }
44
+        WritableArray cookieList = Arguments.createArray();
45
+        if(cookies != null) {
46
+            for(Cookie c : cookies){
47
+                cookieList.pushString(c.toString());
48
+            }
49
+            return cookieList;
50
+        }
51
+        return null;
52
+    }
53
+}

+ 3
- 2
src/index.js View File

@@ -24,6 +24,7 @@ import base64 from 'base-64'
24 24
 import polyfill from './polyfill'
25 25
 import android from './android'
26 26
 import ios from './ios'
27
+import net from './net'
27 28
 import JSONStream from './json-stream'
28 29
 const {
29 30
   RNFetchBlobSession,
@@ -41,10 +42,9 @@ const {
41 42
   cp
42 43
 } = fs
43 44
 
44
-
45 45
 const Blob = polyfill.Blob
46 46
 const emitter = DeviceEventEmitter
47
-const RNFetchBlob:RNFetchBlobNative = NativeModules.RNFetchBlob
47
+const RNFetchBlob= NativeModules.RNFetchBlob
48 48
 
49 49
 // register message channel event handler.
50 50
 emitter.addListener("RNFetchBlobMessage", (e) => {
@@ -549,6 +549,7 @@ export default {
549 549
   session,
550 550
   fs,
551 551
   wrap,
552
+  net,
552 553
   polyfill,
553 554
   JSONStream
554 555
 }

+ 6
- 2
src/ios/RNFetchBlob/RNFetchBlob.m View File

@@ -91,6 +91,7 @@ RCT_EXPORT_METHOD(fetchBlobForm:(NSDictionary *)options
91 91
 
92 92
 }
93 93
 
94
+
94 95
 // Fetch blob data request
95 96
 RCT_EXPORT_METHOD(fetchBlob:(NSDictionary *)options
96 97
                   taskId:(NSString *)taskId
@@ -473,8 +474,11 @@ RCT_EXPORT_METHOD(previewDocument:(NSString*)uri scheme:(NSString *)scheme resol
473 474
     return window.rootViewController;
474 475
 }
475 476
 
476
-
477
-#pragma mark RNFetchBlob private methods
477
+# pragma mark - getCookies
478
+RCT_EXPORT_METHOD(getCookies:(NSString *)url resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject
479
+{
480
+    resolve([RNFetchBlobNetwork getCookies:url]);
481
+})
478 482
 
479 483
 
480 484
 @end

+ 1
- 0
src/ios/RNFetchBlobNetwork.h View File

@@ -44,6 +44,7 @@ typedef void(^DataTaskCompletionHander) (NSData * _Nullable resp, NSURLResponse
44 44
 - (void) sendRequest:(NSDictionary  * _Nullable )options contentLength:(long)contentLength bridge:(RCTBridge * _Nullable)bridgeRef taskId:(NSString * _Nullable)taskId withRequest:(NSURLRequest * _Nullable)req callback:(_Nullable RCTResponseSenderBlock) callback;
45 45
 + (void) enableProgressReport:(NSString *) taskId config:(RNFetchBlobProgress *)config;
46 46
 + (void) enableUploadProgress:(NSString *) taskId config:(RNFetchBlobProgress *)config;
47
++ (NSArray *) getCookies:(NSString *) url;
47 48
 
48 49
 
49 50
 

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

@@ -28,6 +28,7 @@
28 28
 
29 29
 NSMapTable * taskTable;
30 30
 NSMapTable * expirationTable;
31
+NSMapTable * cookiesTable;
31 32
 NSMutableDictionary * progressTable;
32 33
 NSMutableDictionary * uploadProgressTable;
33 34
 
@@ -93,9 +94,55 @@ NSOperationQueue *taskQueue;
93 94
     {
94 95
         uploadProgressTable = [[NSMutableDictionary alloc] init];
95 96
     }
97
+    if(cookiesTable == nil)
98
+    {
99
+        cookiesTable = [[NSMapTable alloc] init];
100
+    }
96 101
     return self;
97 102
 }
98 103
 
104
++ (NSArray *) getCookies:(NSString *) url
105
+{
106
+    NSString * hostname = [[NSURL URLWithString:url] host];
107
+    NSMutableArray * cookies = [NSMutableArray new];
108
+    NSArray * list = [cookiesTable objectForKey:hostname];
109
+    for(NSHTTPCookie * cookie in list)
110
+    {
111
+        NSMutableString * cookieStr = [[NSMutableString alloc] init];
112
+        [cookieStr appendString:cookie.name];
113
+        [cookieStr appendString:@"="];
114
+        [cookieStr appendString:cookie.value];
115
+        
116
+        if(cookie.expiresDate == nil) {
117
+            [cookieStr appendString:@"; max-age=0"];
118
+        }
119
+        else {
120
+            [cookieStr appendString:@"; expires="];
121
+            NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
122
+            [dateFormatter setDateFormat:@"EEE, dd MM yyyy HH:mm:ss ZZZ"];
123
+            NSString *strDate = [dateFormatter stringFromDate:cookie.expiresDate];
124
+            [cookieStr appendString:strDate];
125
+        }
126
+        
127
+        
128
+        [cookieStr appendString:@"; domain="];
129
+        [cookieStr appendString:hostname];
130
+        [cookieStr appendString:@"; path="];
131
+        [cookieStr appendString:cookie.path];
132
+        
133
+        
134
+        if (cookie.isSecure) {
135
+            [cookieStr appendString:@"; secure"];
136
+        }
137
+        
138
+        if (cookie.isHTTPOnly) {
139
+            [cookieStr appendString:@"; httponly"];
140
+        }
141
+        [cookies addObject:cookieStr];
142
+    }
143
+    return cookies;
144
+}
145
+
99 146
 + (void) enableProgressReport:(NSString *) taskId config:(RNFetchBlobProgress *)config
100 147
 {
101 148
     [progressTable setValue:config forKey:taskId];
@@ -253,6 +300,8 @@ NSOperationQueue *taskQueue;
253 300
 
254 301
 #pragma mark NSURLSession delegate methods
255 302
 
303
+
304
+#pragma mark - Received Response
256 305
 // set expected content length on response received
257 306
 - (void) URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler
258 307
 {
@@ -332,12 +381,23 @@ NSOperationQueue *taskQueue;
332 381
                      @"status": [NSString stringWithFormat:@"%d", statusCode ]
333 382
                     };
334 383
 
384
+#pragma mark - handling cookies
385
+        // # 153 get cookies
386
+        if(response.URL != nil)
387
+        {
388
+            NSArray<NSHTTPCookie *> * cookies = [NSHTTPCookie cookiesWithResponseHeaderFields: headers forURL:response.URL];
389
+            if(cookies != nil && [cookies count] > 0) {
390
+                [cookiesTable setObject:cookies forKey:response.URL.host];
391
+            }
392
+        }
393
+        
335 394
         [self.bridge.eventDispatcher
336 395
          sendDeviceEventWithName: EVENT_STATE_CHANGE
337 396
          body:respInfo
338 397
         ];
339 398
         headers = nil;
340 399
         respInfo = nil;
400
+
341 401
     }
342 402
     else
343 403
         NSLog(@"oops");

+ 26
- 0
src/net.js View File

@@ -0,0 +1,26 @@
1
+// Copyright 2016 wkh237@github. All rights reserved.
2
+// Use of this source code is governed by a MIT-style license that can be
3
+// found in the LICENSE file.
4
+// @flow
5
+
6
+import {
7
+  NativeModules,
8
+  DeviceEventEmitter,
9
+  Platform,
10
+  NativeAppEventEmitter,
11
+} from 'react-native'
12
+
13
+const RNFetchBlob = NativeModules.RNFetchBlob
14
+
15
+/**
16
+ * Get cookie according to the given url.
17
+ * @param  {string} url HTTP URL string.
18
+ * @return {Promise<Array<String>>}     Cookies of a specific domain.
19
+ */
20
+function getCookies(url:string):Promise<Array<String>> {
21
+  return RNFetchBlob.getCookies(url)
22
+}
23
+
24
+export default {
25
+  getCookies
26
+}

+ 71
- 54
test/test-0.10.0.js View File

@@ -26,65 +26,82 @@ const dirs = RNFetchBlob.fs.dirs
26 26
 let prefix = ((Platform.OS === 'android') ? 'file://' : '')
27 27
 let begin = Date.now()
28 28
 
29
-describe('json stream via HTTP', (report, done) => {
29
+// describe('json stream via HTTP', (report, done) => {
30
+//
31
+//   let count = 0
32
+//   JSONStream(`${TEST_SERVER_URL}/public/json-dummy.json`).node('name', (name) => {
33
+//     count++
34
+//     if(Date.now() - begin < 100)
35
+//     return
36
+//     begin = Date.now()
37
+//     report(<Info key="report" uid="100">
38
+//       <Text>{count} records</Text>
39
+//     </Info>)
40
+//     done()
41
+//   })
42
+//
43
+// })
44
+//
45
+// describe('json stream via fs', (report, done) => {
46
+//
47
+//   let fetch2 = new RNFetchBlob.polyfill.Fetch({
48
+//     auto : true
49
+//   })
50
+//   let res = null
51
+//   let count = 0
52
+//
53
+//   RNFetchBlob.config({
54
+//     fileCache : true
55
+//   })
56
+//   .fetch('GET',`${TEST_SERVER_URL}/public/json-dummy.json`)
57
+//   .then((resp) => {
58
+//     res = resp
59
+//     JSONStream({
60
+//       url : RNFetchBlob.wrap(res.path()),
61
+//       headers : { bufferSize : 10240 }
62
+//     }).node('name', (name) => {
63
+//       count++
64
+//       if(Date.now() - begin < 100)
65
+//       return
66
+//       begin = Date.now()
67
+//       report(<Info key="report" uid="100">
68
+//         <Text>{count} records</Text>
69
+//       </Info>)
70
+//       done()
71
+//     })
72
+//   })
73
+// })
74
+//
75
+// describe('issue #102', (report, done) => {
76
+//   let tmp = null
77
+//   RNFetchBlob.config({ fileCache: true, appendExt : 'png' })
78
+//     .fetch('GET', `${TEST_SERVER_URL}/public/github.png`)
79
+//     .then((res) => {
80
+//       tmp = res
81
+//       RNFetchBlob.ios.previewDocument(res.path())
82
+//       return RNFetchBlob.fetch('POST', `${TEST_SERVER_URL}/upload-form`, {},
83
+//       [{ name : String(1), data : RNFetchBlob.wrap(res.path()), filename: '#102-test-image.png' }])
84
+//     })
85
+//     .then((res) =>  tmp.flush())
86
+//     .then(() => {
87
+//       done()
88
+//     })
89
+//
90
+// })
30 91
 
31
-  let count = 0
32
-  JSONStream(`${TEST_SERVER_URL}/public/json-dummy.json`).node('name', (name) => {
33
-    count++
34
-    if(Date.now() - begin < 100)
35
-    return
36
-    begin = Date.now()
37
-    report(<Info key="report" uid="100">
38
-      <Text>{count} records</Text>
39
-    </Info>)
40
-    done()
41
-  })
42
-
43
-})
44 92
 
45
-describe('json stream via fs', (report, done) => {
46
-
47
-  let fetch2 = new RNFetchBlob.polyfill.Fetch({
48
-    auto : true
49
-  })
50
-  let res = null
51
-  let count = 0
93
+describe('cookie test', (report, done) => {
52 94
 
53
-  RNFetchBlob.config({
54
-    fileCache : true
95
+  RNFetchBlob.fetch('GET', `${TEST_SERVER_URL}/cookie`)
96
+  .then((res) => {
97
+    return RNFetchBlob.fetch('GET', `${TEST_SERVER_URL}/xhr-header`)
55 98
   })
56
-  .fetch('GET',`${TEST_SERVER_URL}/public/json-dummy.json`)
57
-  .then((resp) => {
58
-    res = resp
59
-    JSONStream({
60
-      url : RNFetchBlob.wrap(res.path()),
61
-      headers : { bufferSize : 10240 }
62
-    }).node('name', (name) => {
63
-      count++
64
-      if(Date.now() - begin < 100)
65
-      return
66
-      begin = Date.now()
67
-      report(<Info key="report" uid="100">
68
-        <Text>{count} records</Text>
69
-      </Info>)
70
-      done()
99
+  .then((res) => {
100
+    console.log(res)
101
+    RNFetchBlob.net.getCookies(`${TEST_SERVER_URL}`)
102
+    .then((cookies) => {
103
+      console.log(cookies)
71 104
     })
72 105
   })
73
-})
74
-
75
-describe('issue #102', (report, done) => {
76
-  let tmp = null
77
-  RNFetchBlob.config({ fileCache: true, appendExt : 'png' })
78
-    .fetch('GET', `${TEST_SERVER_URL}/public/github.png`)
79
-    .then((res) => {
80
-      tmp = res
81
-      RNFetchBlob.ios.previewDocument(res.path())
82
-      return RNFetchBlob.fetch('POST', `${TEST_SERVER_URL}/upload-form`, {},
83
-      [{ name : String(1), data : RNFetchBlob.wrap(res.path()), filename: '#102-test-image.png' }])
84
-    })
85
-    .then((res) =>  tmp.flush())
86
-    .then(() => {
87
-      done()
88
-    })
89 106
 
90 107
 })