Browse Source

Add XMLHttpRequest automatic response data handling strategy #44

Ben Hsieh 8 years ago
parent
commit
2077e73ad2

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

16
     public Boolean trusty;
16
     public Boolean trusty;
17
     public String key;
17
     public String key;
18
     public String mime;
18
     public String mime;
19
+    public Boolean auto;
19
 
20
 
20
     RNFetchBlobConfig(ReadableMap options) {
21
     RNFetchBlobConfig(ReadableMap options) {
21
         if(options == null)
22
         if(options == null)
29
         }
30
         }
30
         this.key = options.hasKey("key") ? options.getString("key") : null;
31
         this.key = options.hasKey("key") ? options.getString("key") : null;
31
         this.mime = options.hasKey("contentType") ? options.getString("contentType") : null;
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 View File

23
 import java.io.ByteArrayInputStream;
23
 import java.io.ByteArrayInputStream;
24
 import java.io.File;
24
 import java.io.File;
25
 import java.io.FileInputStream;
25
 import java.io.FileInputStream;
26
+import java.io.FileOutputStream;
26
 import java.io.IOException;
27
 import java.io.IOException;
27
 import java.io.InputStream;
28
 import java.io.InputStream;
28
 import java.net.MalformedURLException;
29
 import java.net.MalformedURLException;
311
         switch (responseType) {
312
         switch (responseType) {
312
             case KeepInMemory:
313
             case KeepInMemory:
313
                 try {
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
                 } catch (IOException e) {
338
                 } catch (IOException e) {
317
                     callback.invoke("RNFetchBlob failed to encode response data to BASE64 string.", null);
339
                     callback.invoke("RNFetchBlob failed to encode response data to BASE64 string.", null);
318
                 }
340
                 }
367
         return info;
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
     private String getHeaderIgnoreCases(Headers headers, String field) {
399
     private String getHeaderIgnoreCases(Headers headers, String field) {
371
         String val = headers.get(field);
400
         String val = headers.get(field);
372
         if(val != null) return val;
401
         if(val != null) return val;

+ 2
- 1
src/index.js View File

154
       else {
154
       else {
155
         let rnfbEncode = 'base64'
155
         let rnfbEncode = 'base64'
156
         // response data is saved to storage
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
           rnfbEncode = 'path'
159
           rnfbEncode = 'path'
159
           if(options.session)
160
           if(options.session)
160
             session(options.session).add(data)
161
             session(options.session).add(data)

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

185
             else
185
             else
186
             {
186
             {
187
                 respType = @"blob";
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
         else
195
         else

+ 10
- 1
src/polyfill/XMLHttpRequest.js View File

33
   _statusText : string;
33
   _statusText : string;
34
   _timeout : number = 0;
34
   _timeout : number = 0;
35
   _upload : XMLHttpRequestEventTarget;
35
   _upload : XMLHttpRequestEventTarget;
36
+  _sendFlag : boolean = false;
36
 
37
 
37
   // RNFetchBlob compatible data structure
38
   // RNFetchBlob compatible data structure
38
   _config : RNFetchBlobConfig;
39
   _config : RNFetchBlobConfig;
86
    * @param  {any} body Body in RNfetchblob flavor
87
    * @param  {any} body Body in RNfetchblob flavor
87
    */
88
    */
88
   send(body) {
89
   send(body) {
90
+    this._sendFlag = true
89
     log.verbose('XMLHttpRequest send ', body)
91
     log.verbose('XMLHttpRequest send ', body)
90
     let {_method, _url, _headers } = this
92
     let {_method, _url, _headers } = this
91
     log.verbose('sending request with args', _method, _url, _headers, body)
93
     log.verbose('sending request with args', _method, _url, _headers, body)
101
     if(this.onloadstart)
103
     if(this.onloadstart)
102
       this.onloadstart()
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
     this._task
108
     this._task
106
         .stateChange(this._headerReceived.bind(this))
109
         .stateChange(this._headerReceived.bind(this))
107
         .uploadProgress(this._progressEvent.bind(this))
110
         .uploadProgress(this._progressEvent.bind(this))
117
 
120
 
118
   setRequestHeader(name, value) {
121
   setRequestHeader(name, value) {
119
     log.verbose('XMLHttpRequest set header', name, value)
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
     this._headers[name] = value
129
     this._headers[name] = value
121
   }
130
   }
122
 
131
 

+ 1
- 0
src/types.js View File

47
   state : number,
47
   state : number,
48
   headers : any,
48
   headers : any,
49
   status : number,
49
   status : number,
50
+  respType : 'text' | 'blob' | '' | 'json'
50
   rnfbEncode : 'path' | 'base64' | 'ascii' | 'utf8'
51
   rnfbEncode : 'path' | 'base64' | 'ascii' | 'utf8'
51
 }
52
 }
52
 
53