@@ -275,7 +275,7 @@ else if(this.options.fileCache == true)
275275
276276 final Request req = builder .build ();
277277
278- // create response handler
278+ // Create response body depends on the responseType
279279 clientBuilder .addInterceptor (new Interceptor () {
280280 @ Override
281281 public Response intercept (Chain chain ) throws IOException {
@@ -304,35 +304,36 @@ public Response intercept(Chain chain) throws IOException {
304304 break ;
305305 }
306306 return originalResponse .newBuilder ().body (extended ).build ();
307- } catch (SocketTimeoutException ex ) {
307+ } catch (Exception ex ) {
308308 timeout = true ;
309309 }
310310 return chain .proceed (chain .request ());
311311 }
312312 });
313313
314+
314315 if (options .timeout > 0 ) {
315316 clientBuilder .connectTimeout (options .timeout , TimeUnit .MILLISECONDS );
316317 clientBuilder .readTimeout (options .timeout , TimeUnit .MILLISECONDS );
317318 }
318- else {
319- clientBuilder .connectTimeout (-1 , TimeUnit .MILLISECONDS );
320- clientBuilder .readTimeout (-1 , TimeUnit .MILLISECONDS );
321- }
319+
322320 clientBuilder .connectionPool (pool );
323321 clientBuilder .retryOnConnectionFailure (false );
322+ clientBuilder .followRedirects (true );
323+
324324 OkHttpClient client = clientBuilder .build ();
325325 Call call = client .newCall (req );
326326 taskTable .put (taskId , call );
327327 call .enqueue (new okhttp3 .Callback () {
328328
329329 @ Override
330330 public void onFailure (Call call , IOException e ) {
331+ cancelTask (taskId );
331332 if (respInfo == null ) {
332333 respInfo = Arguments .createMap ();
333334 }
334335
335- // check if this error caused by timeout
336+ // check if this error caused by socket timeout
336337 if (e .getClass ().equals (SocketTimeoutException .class )) {
337338 respInfo .putBoolean ("timeout" , true );
338339 callback .invoke ("request timed out." , respInfo , null );
@@ -345,7 +346,6 @@ public void onFailure(Call call, IOException e) {
345346 @ Override
346347 public void onResponse (Call call , Response response ) throws IOException {
347348 ReadableMap notifyConfig = options .addAndroidDownloads ;
348- respInfo = getResponseInfo (response );
349349 // Download manager settings
350350 if (notifyConfig != null ) {
351351 String title = "" , desc = "" , mime = "text/plain" ;
@@ -371,7 +371,7 @@ public void onResponse(Call call, Response response) throws IOException {
371371 } catch (Exception error ) {
372372 error .printStackTrace ();
373373 taskTable .remove (taskId );
374- callback .invoke ("RNFetchBlob request error: " + error .getMessage () + error .getCause (), this . respInfo );
374+ callback .invoke ("RNFetchBlob request error: " + error .getMessage () + error .getCause ());
375375 }
376376 }
377377
@@ -392,14 +392,15 @@ private void removeTaskInfo() {
392392 * @param resp OkHttp response object
393393 */
394394 private void done (Response resp ) {
395- emitStateEvent (getResponseInfo (resp ));
395+ boolean isBlobResp = isBlobResponse (resp );
396+ emitStateEvent (getResponseInfo (resp , isBlobResp ));
396397 switch (responseType ) {
397398 case KeepInMemory :
398399 try {
399400 // For XMLHttpRequest, automatic response data storing strategy, when response
400401 // header is not `application/json` or `text/plain`, write response data to
401402 // file system.
402- if (isBlobResponse ( resp ) && options .auto == true ) {
403+ if (isBlobResp && options .auto == true ) {
403404 String dest = RNFetchBlobFS .getTmpPath (ctx , taskId );
404405 InputStream ins = resp .body ().byteStream ();
405406 FileOutputStream os = new FileOutputStream (new File (dest ));
@@ -412,27 +413,26 @@ private void done(Response resp) {
412413 }
413414 ins .close ();
414415 os .close ();
415- WritableMap info = getResponseInfo (resp );
416- callback .invoke (null , info , dest );
416+ callback .invoke (null , null , dest );
417417 }
418418 else {
419- // we should check if the response data is a UTF8 string, because BASE64
420- // encoding will somehow break the UTF8 string format. In order to encode
421- // UTF8 string correctly, we should do URL encoding before BASE64.
419+ // #73 Check if the response data contains valid UTF8 string, since BASE64
420+ // encoding will somehow break the UTF8 string format, to encode UTF8
421+ // string correctly, we should do URL encoding before BASE64.
422422 String utf8Str ;
423423 byte [] b = resp .body ().bytes ();
424424 CharsetEncoder encoder = Charset .forName ("UTF-8" ).newEncoder ();
425425 try {
426426 encoder .encode (ByteBuffer .wrap (b ).asCharBuffer ());
427427 // if the data can be encoded to UTF8 append URL encode
428- b = URLEncoder .encode (new String (b ), "UTF-8" ).getBytes ();
428+ b = URLEncoder .encode (new String (b ), "UTF-8" ).replace ( "+" , "%20" ). getBytes ();
429429 }
430430 // This usually mean the data is binary data
431431 catch (CharacterCodingException e ) {
432432
433433 }
434434 finally {
435- callback .invoke (null , getResponseInfo ( resp ) , android .util .Base64 .encodeToString (b , Base64 .NO_WRAP ));
435+ callback .invoke (null , null , android .util .Base64 .encodeToString (b , Base64 .NO_WRAP ));
436436 }
437437 }
438438 } catch (IOException e ) {
@@ -441,15 +441,18 @@ private void done(Response resp) {
441441 break ;
442442 case FileStorage :
443443 try {
444+ // In order to write response data to `destPath` we have to invoke this method.
445+ // It uses customized response body which is able to report download progress
446+ // and write response data to destination path.
444447 resp .body ().bytes ();
445448 } catch (Exception ignored ) {
446449
447450 }
448- callback .invoke (null , getResponseInfo ( resp ) , this .destPath );
451+ callback .invoke (null , null , this .destPath );
449452 break ;
450453 default :
451454 try {
452- callback .invoke (null , getResponseInfo ( resp ) , new String (resp .body ().bytes (), "UTF-8" ));
455+ callback .invoke (null , null , new String (resp .body ().bytes (), "UTF-8" ));
453456 } catch (IOException e ) {
454457 callback .invoke ("RNFetchBlob failed to encode response data to UTF8 string." , null );
455458 }
@@ -458,17 +461,27 @@ private void done(Response resp) {
458461 removeTaskInfo ();
459462 }
460463
464+ /**
465+ * Invoke this method to enable download progress reporting.
466+ * @param taskId Task ID of the HTTP task.
467+ * @return Task ID of the target task
468+ */
461469 public static boolean isReportProgress (String taskId ) {
462470 if (!progressReport .containsKey (taskId )) return false ;
463471 return progressReport .get (taskId );
464472 }
465473
474+ /**
475+ * Invoke this method to enable download progress reporting.
476+ * @param taskId Task ID of the HTTP task.
477+ * @return Task ID of the target task
478+ */
466479 public static boolean isReportUploadProgress (String taskId ) {
467480 if (!uploadProgressReport .containsKey (taskId )) return false ;
468481 return uploadProgressReport .get (taskId );
469482 }
470483
471- private WritableMap getResponseInfo (Response resp ) {
484+ private WritableMap getResponseInfo (Response resp , boolean isBlobResp ) {
472485 WritableMap info = Arguments .createMap ();
473486 info .putInt ("status" , resp .code ());
474487 info .putString ("state" , "2" );
@@ -480,26 +493,36 @@ private WritableMap getResponseInfo(Response resp) {
480493 }
481494 info .putMap ("headers" , headers );
482495 Headers h = resp .headers ();
483- if (getHeaderIgnoreCases (h , "content-type" ).equalsIgnoreCase ("text/" )) {
496+ if (isBlobResp ) {
497+ info .putString ("respType" , "blob" );
498+ }
499+ else if (getHeaderIgnoreCases (h , "content-type" ).equalsIgnoreCase ("text/" )) {
484500 info .putString ("respType" , "text" );
485501 }
486502 else if (getHeaderIgnoreCases (h , "content-type" ).contains ("application/json" )) {
487503 info .putString ("respType" , "json" );
488504 }
489- else if (getHeaderIgnoreCases (h , "content-type" ).length () < 1 ) {
490- info .putString ("respType" , "blob" );
491- }
492505 else {
493- info .putString ("respType" , "text " );
506+ info .putString ("respType" , "" );
494507 }
495508 return info ;
496509 }
497510
498511 private boolean isBlobResponse (Response resp ) {
499512 Headers h = resp .headers ();
500- boolean isText = !getHeaderIgnoreCases (h , "content-type" ).equalsIgnoreCase ("text/" );
501- boolean isJSON = !getHeaderIgnoreCases (h , "content-type" ).equalsIgnoreCase ("application/json" );
502- return !(isJSON || isText );
513+ String ctype = getHeaderIgnoreCases (h , "Content-Type" );
514+ boolean isText = !ctype .equalsIgnoreCase ("text/" );
515+ boolean isJSON = !ctype .equalsIgnoreCase ("application/json" );
516+ boolean isCustomBinary = false ;
517+ if (options .binaryContentTypes != null ) {
518+ for (int i = 0 ; i < options .binaryContentTypes .size ();i ++) {
519+ if (ctype .toLowerCase ().contains (options .binaryContentTypes .getString (i ).toLowerCase ())) {
520+ isCustomBinary = true ;
521+ break ;
522+ }
523+ }
524+ }
525+ return (!(isJSON || isText )) || isCustomBinary ;
503526 }
504527
505528 private String getHeaderIgnoreCases (Headers headers , String field ) {
0 commit comments