소스 검색

Add XMLHttpRequest automatic response data handling strategy #44

Ben Hsieh 8 년 전
부모
커밋
2077e73ad2

+ 2
- 0
src/android/src/main/java/com/RNFetchBlob/RNFetchBlobConfig.java 파일 보기

@@ -16,6 +16,7 @@ public class RNFetchBlobConfig {
16 16
     public Boolean trusty;
17 17
     public String key;
18 18
     public String mime;
19
+    public Boolean auto;
19 20
 
20 21
     RNFetchBlobConfig(ReadableMap options) {
21 22
         if(options == null)
@@ -29,6 +30,7 @@ public class RNFetchBlobConfig {
29 30
         }
30 31
         this.key = options.hasKey("key") ? options.getString("key") : null;
31 32
         this.mime = options.hasKey("contentType") ? options.getString("contentType") : null;
33
+        this.auto = options.hasKey("auto") ? options.getBoolean("auto") : false;
32 34
     }
33 35
 
34 36
 }

+ 31
- 2
src/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java 파일 보기

@@ -23,6 +23,7 @@ import com.facebook.react.bridge.WritableMap;
23 23
 import java.io.ByteArrayInputStream;
24 24
 import java.io.File;
25 25
 import java.io.FileInputStream;
26
+import java.io.FileOutputStream;
26 27
 import java.io.IOException;
27 28
 import java.io.InputStream;
28 29
 import java.net.MalformedURLException;
@@ -311,8 +312,29 @@ public class RNFetchBlobReq extends BroadcastReceiver implements Runnable {
311 312
         switch (responseType) {
312 313
             case KeepInMemory:
313 314
                 try {
314
-                    byte [] b = resp.body().bytes();
315
-                    callback.invoke(null, getResponseInfo(resp), android.util.Base64.encodeToString(b,Base64.NO_WRAP));
315
+                    // For XMLHttpRequest, automatic response data storing strategy, when response
316
+                    // header is not `application/json` or `text/plain`, write response data to
317
+                    // file system.
318
+                    if(isBlobResponse(resp) && options.auto == true) {
319
+                        String dest = RNFetchBlobFS.getTmpPath(ctx, taskId);
320
+                        InputStream ins = resp.body().byteStream();
321
+                        FileOutputStream os = new FileOutputStream(new File(dest));
322
+                        byte [] buffer = new byte[10240];
323
+                        int read = ins.read(buffer);
324
+                        os.write(buffer,0,read);
325
+                        while(read > 0) {
326
+                            os.write(buffer,0,read);
327
+                            read = ins.read(buffer);
328
+                        }
329
+                        ins.close();
330
+                        os.close();
331
+                        WritableMap info = getResponseInfo(resp);
332
+                        callback.invoke(null, info, dest);
333
+                    }
334
+                    else {
335
+                        byte[] b = resp.body().bytes();
336
+                        callback.invoke(null, getResponseInfo(resp), android.util.Base64.encodeToString(b, Base64.NO_WRAP));
337
+                    }
316 338
                 } catch (IOException e) {
317 339
                     callback.invoke("RNFetchBlob failed to encode response data to BASE64 string.", null);
318 340
                 }
@@ -367,6 +389,13 @@ public class RNFetchBlobReq extends BroadcastReceiver implements Runnable {
367 389
         return info;
368 390
     }
369 391
 
392
+    private boolean isBlobResponse(Response resp) {
393
+        Headers h = resp.headers();
394
+        boolean isText = !getHeaderIgnoreCases(h, "content-type").equalsIgnoreCase("text/plain");
395
+        boolean isJSON = !getHeaderIgnoreCases(h, "content-type").equalsIgnoreCase("application/json");
396
+        return  !(isJSON || isText);
397
+    }
398
+
370 399
     private String getHeaderIgnoreCases(Headers headers, String field) {
371 400
         String val = headers.get(field);
372 401
         if(val != null) return val;

+ 2
- 1
src/index.js 파일 보기

@@ -154,7 +154,8 @@ function fetch(...args:any):Promise {
154 154
       else {
155 155
         let rnfbEncode = 'base64'
156 156
         // response data is saved to storage
157
-        if(options.path || options.fileCache || options.addAndroidDownloads || options.key) {
157
+        if(options.path || options.fileCache || options.addAndroidDownloads
158
+          || options.key || options.auto && info.respType === 'blob') {
158 159
           rnfbEncode = 'path'
159 160
           if(options.session)
160 161
             session(options.session).add(data)

+ 5
- 0
src/ios/RNFetchBlobNetwork.m 파일 보기

@@ -185,6 +185,11 @@ NSOperationQueue *taskQueue;
185 185
             else
186 186
             {
187 187
                 respType = @"blob";
188
+                // for XMLHttpRequest, switch response data handling strategy automatically
189
+                if([options valueForKey:@"auto"] == YES) {
190
+                    respFile = YES;
191
+                    destPath = [RNFetchBlobFS getTempPath:taskId withExtension:@""];
192
+                }
188 193
             }
189 194
         }
190 195
         else

+ 10
- 1
src/polyfill/XMLHttpRequest.js 파일 보기

@@ -33,6 +33,7 @@ export default class XMLHttpRequest extends XMLHttpRequestEventTarget{
33 33
   _statusText : string;
34 34
   _timeout : number = 0;
35 35
   _upload : XMLHttpRequestEventTarget;
36
+  _sendFlag : boolean = false;
36 37
 
37 38
   // RNFetchBlob compatible data structure
38 39
   _config : RNFetchBlobConfig;
@@ -86,6 +87,7 @@ export default class XMLHttpRequest extends XMLHttpRequestEventTarget{
86 87
    * @param  {any} body Body in RNfetchblob flavor
87 88
    */
88 89
   send(body) {
90
+    this._sendFlag = true
89 91
     log.verbose('XMLHttpRequest send ', body)
90 92
     let {_method, _url, _headers } = this
91 93
     log.verbose('sending request with args', _method, _url, _headers, body)
@@ -101,7 +103,8 @@ export default class XMLHttpRequest extends XMLHttpRequestEventTarget{
101 103
     if(this.onloadstart)
102 104
       this.onloadstart()
103 105
 
104
-    this._task = RNFetchBlob.fetch(_method, _url, _headers, body)
106
+    this._task = RNFetchBlob.config({ auto: true })
107
+                            .fetch(_method, _url, _headers, body)
105 108
     this._task
106 109
         .stateChange(this._headerReceived.bind(this))
107 110
         .uploadProgress(this._progressEvent.bind(this))
@@ -117,6 +120,12 @@ export default class XMLHttpRequest extends XMLHttpRequestEventTarget{
117 120
 
118 121
   setRequestHeader(name, value) {
119 122
     log.verbose('XMLHttpRequest set header', name, value)
123
+    if(this._readyState !== OPENED && this._sendFlag) {
124
+      throw `InvalidStateError : Calling setRequestHeader in wrong state  ${this._readyState}`
125
+    }
126
+    if(/[^\u0000-\u00ff]/.test(name) || typeof name !== 'string') {
127
+      throw `TypeError : Invalid header field name ${name}`
128
+    }
120 129
     this._headers[name] = value
121 130
   }
122 131
 

+ 1
- 0
src/types.js 파일 보기

@@ -47,6 +47,7 @@ type RNFetchBlobResponseInfo = {
47 47
   state : number,
48 48
   headers : any,
49 49
   status : number,
50
+  respType : 'text' | 'blob' | '' | 'json'
50 51
   rnfbEncode : 'path' | 'base64' | 'ascii' | 'utf8'
51 52
 }
52 53