@@ -275,7 +275,7 @@ else if(this.options.fileCache == true)
275
275
276
276
final Request req = builder .build ();
277
277
278
- // create response handler
278
+ // Create response body depends on the responseType
279
279
clientBuilder .addInterceptor (new Interceptor () {
280
280
@ Override
281
281
public Response intercept (Chain chain ) throws IOException {
@@ -304,35 +304,36 @@ public Response intercept(Chain chain) throws IOException {
304
304
break ;
305
305
}
306
306
return originalResponse .newBuilder ().body (extended ).build ();
307
- } catch (SocketTimeoutException ex ) {
307
+ } catch (Exception ex ) {
308
308
timeout = true ;
309
309
}
310
310
return chain .proceed (chain .request ());
311
311
}
312
312
});
313
313
314
+
314
315
if (options .timeout > 0 ) {
315
316
clientBuilder .connectTimeout (options .timeout , TimeUnit .MILLISECONDS );
316
317
clientBuilder .readTimeout (options .timeout , TimeUnit .MILLISECONDS );
317
318
}
318
- else {
319
- clientBuilder .connectTimeout (-1 , TimeUnit .MILLISECONDS );
320
- clientBuilder .readTimeout (-1 , TimeUnit .MILLISECONDS );
321
- }
319
+
322
320
clientBuilder .connectionPool (pool );
323
321
clientBuilder .retryOnConnectionFailure (false );
322
+ clientBuilder .followRedirects (true );
323
+
324
324
OkHttpClient client = clientBuilder .build ();
325
325
Call call = client .newCall (req );
326
326
taskTable .put (taskId , call );
327
327
call .enqueue (new okhttp3 .Callback () {
328
328
329
329
@ Override
330
330
public void onFailure (Call call , IOException e ) {
331
+ cancelTask (taskId );
331
332
if (respInfo == null ) {
332
333
respInfo = Arguments .createMap ();
333
334
}
334
335
335
- // check if this error caused by timeout
336
+ // check if this error caused by socket timeout
336
337
if (e .getClass ().equals (SocketTimeoutException .class )) {
337
338
respInfo .putBoolean ("timeout" , true );
338
339
callback .invoke ("request timed out." , respInfo , null );
@@ -345,7 +346,6 @@ public void onFailure(Call call, IOException e) {
345
346
@ Override
346
347
public void onResponse (Call call , Response response ) throws IOException {
347
348
ReadableMap notifyConfig = options .addAndroidDownloads ;
348
- respInfo = getResponseInfo (response );
349
349
// Download manager settings
350
350
if (notifyConfig != null ) {
351
351
String title = "" , desc = "" , mime = "text/plain" ;
@@ -371,7 +371,7 @@ public void onResponse(Call call, Response response) throws IOException {
371
371
} catch (Exception error ) {
372
372
error .printStackTrace ();
373
373
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 ());
375
375
}
376
376
}
377
377
@@ -392,14 +392,15 @@ private void removeTaskInfo() {
392
392
* @param resp OkHttp response object
393
393
*/
394
394
private void done (Response resp ) {
395
- emitStateEvent (getResponseInfo (resp ));
395
+ boolean isBlobResp = isBlobResponse (resp );
396
+ emitStateEvent (getResponseInfo (resp , isBlobResp ));
396
397
switch (responseType ) {
397
398
case KeepInMemory :
398
399
try {
399
400
// For XMLHttpRequest, automatic response data storing strategy, when response
400
401
// header is not `application/json` or `text/plain`, write response data to
401
402
// file system.
402
- if (isBlobResponse ( resp ) && options .auto == true ) {
403
+ if (isBlobResp && options .auto == true ) {
403
404
String dest = RNFetchBlobFS .getTmpPath (ctx , taskId );
404
405
InputStream ins = resp .body ().byteStream ();
405
406
FileOutputStream os = new FileOutputStream (new File (dest ));
@@ -412,27 +413,26 @@ private void done(Response resp) {
412
413
}
413
414
ins .close ();
414
415
os .close ();
415
- WritableMap info = getResponseInfo (resp );
416
- callback .invoke (null , info , dest );
416
+ callback .invoke (null , null , dest );
417
417
}
418
418
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.
422
422
String utf8Str ;
423
423
byte [] b = resp .body ().bytes ();
424
424
CharsetEncoder encoder = Charset .forName ("UTF-8" ).newEncoder ();
425
425
try {
426
426
encoder .encode (ByteBuffer .wrap (b ).asCharBuffer ());
427
427
// 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 ();
429
429
}
430
430
// This usually mean the data is binary data
431
431
catch (CharacterCodingException e ) {
432
432
433
433
}
434
434
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 ));
436
436
}
437
437
}
438
438
} catch (IOException e ) {
@@ -441,15 +441,18 @@ private void done(Response resp) {
441
441
break ;
442
442
case FileStorage :
443
443
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.
444
447
resp .body ().bytes ();
445
448
} catch (Exception ignored ) {
446
449
447
450
}
448
- callback .invoke (null , getResponseInfo ( resp ) , this .destPath );
451
+ callback .invoke (null , null , this .destPath );
449
452
break ;
450
453
default :
451
454
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" ));
453
456
} catch (IOException e ) {
454
457
callback .invoke ("RNFetchBlob failed to encode response data to UTF8 string." , null );
455
458
}
@@ -458,17 +461,27 @@ private void done(Response resp) {
458
461
removeTaskInfo ();
459
462
}
460
463
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
+ */
461
469
public static boolean isReportProgress (String taskId ) {
462
470
if (!progressReport .containsKey (taskId )) return false ;
463
471
return progressReport .get (taskId );
464
472
}
465
473
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
+ */
466
479
public static boolean isReportUploadProgress (String taskId ) {
467
480
if (!uploadProgressReport .containsKey (taskId )) return false ;
468
481
return uploadProgressReport .get (taskId );
469
482
}
470
483
471
- private WritableMap getResponseInfo (Response resp ) {
484
+ private WritableMap getResponseInfo (Response resp , boolean isBlobResp ) {
472
485
WritableMap info = Arguments .createMap ();
473
486
info .putInt ("status" , resp .code ());
474
487
info .putString ("state" , "2" );
@@ -480,26 +493,36 @@ private WritableMap getResponseInfo(Response resp) {
480
493
}
481
494
info .putMap ("headers" , headers );
482
495
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/" )) {
484
500
info .putString ("respType" , "text" );
485
501
}
486
502
else if (getHeaderIgnoreCases (h , "content-type" ).contains ("application/json" )) {
487
503
info .putString ("respType" , "json" );
488
504
}
489
- else if (getHeaderIgnoreCases (h , "content-type" ).length () < 1 ) {
490
- info .putString ("respType" , "blob" );
491
- }
492
505
else {
493
- info .putString ("respType" , "text " );
506
+ info .putString ("respType" , "" );
494
507
}
495
508
return info ;
496
509
}
497
510
498
511
private boolean isBlobResponse (Response resp ) {
499
512
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 ;
503
526
}
504
527
505
528
private String getHeaderIgnoreCases (Headers headers , String field ) {
0 commit comments