react-native-blob-util 0.24.9 → 0.24.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,9 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(npm view *)",
5
+ "Bash(npm install *)",
6
+ "Bash(git -C tests/e2e/android-app diff --stat package-lock.json)"
7
+ ]
8
+ }
9
+ }
@@ -63,7 +63,7 @@ android {
63
63
  buildTypes {
64
64
  release {
65
65
  minifyEnabled false
66
- proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
66
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
67
67
  }
68
68
  }
69
69
  compileOptions {
@@ -168,4 +168,4 @@ afterEvaluate { project ->
168
168
  }
169
169
  }
170
170
  }
171
- }
171
+ }
@@ -29,6 +29,7 @@ import java.io.FileOutputStream;
29
29
  import java.io.IOException;
30
30
  import java.io.InputStream;
31
31
  import java.io.OutputStream;
32
+ import java.io.ByteArrayOutputStream;
32
33
  import java.security.MessageDigest;
33
34
  import java.util.ArrayList;
34
35
  import java.util.HashMap;
@@ -251,41 +252,27 @@ class ReactNativeBlobUtilFS {
251
252
  path = resolved;
252
253
  try {
253
254
  byte[] bytes;
254
- int bytesRead;
255
- int length; // max. array length limited to "int", also see https://stackoverflow.com/a/10787175/544779
256
255
 
257
256
  if (resolved != null && resolved.startsWith(ReactNativeBlobUtilConst.FILE_PREFIX_BUNDLE_ASSET)) {
258
257
  String assetName = path.replace(ReactNativeBlobUtilConst.FILE_PREFIX_BUNDLE_ASSET, "");
259
- // This fails should an asset file be >2GB
260
- InputStream in = ReactNativeBlobUtilImpl.RCTContext.getAssets().open(assetName);
261
- length = in.available();
262
- bytes = new byte[length];
263
- bytesRead = in.read(bytes, 0, length);
264
- in.close();
258
+ try (InputStream in = ReactNativeBlobUtilImpl.RCTContext.getAssets().open(assetName)) {
259
+ bytes = readBytesWithLimit(in);
260
+ }
265
261
  }
266
262
  // issue 287
267
263
  else if (resolved == null) {
268
- InputStream in = ReactNativeBlobUtilImpl.RCTContext.getContentResolver().openInputStream(Uri.parse(path));
269
- // TODO See https://developer.android.com/reference/java/io/InputStream.html#available()
270
- // Quote: "Note that while some implementations of InputStream will return the total number of bytes
271
- // in the stream, many will not. It is never correct to use the return value of this method to
272
- // allocate a buffer intended to hold all data in this stream."
273
- length = in.available();
274
- bytes = new byte[length];
275
- bytesRead = in.read(bytes);
276
- in.close();
264
+ try (InputStream in = ReactNativeBlobUtilImpl.RCTContext.getContentResolver().openInputStream(Uri.parse(path))) {
265
+ if (in == null) {
266
+ promise.reject("ENOENT", "No such file '" + path + "'");
267
+ return;
268
+ }
269
+ bytes = readBytesWithLimit(in);
270
+ }
277
271
  } else {
278
272
  File f = new File(path);
279
- length = (int) f.length();
280
- bytes = new byte[length];
281
- FileInputStream in = new FileInputStream(f);
282
- bytesRead = in.read(bytes);
283
- in.close();
284
- }
285
-
286
- if (bytesRead < length) {
287
- promise.reject("EUNSPECIFIED", "Read only " + bytesRead + " bytes of " + length);
288
- return;
273
+ try (FileInputStream in = new FileInputStream(f)) {
274
+ bytes = readBytesWithLimit(in);
275
+ }
289
276
  }
290
277
 
291
278
  if (transformFile) {
@@ -326,6 +313,18 @@ class ReactNativeBlobUtilFS {
326
313
 
327
314
  }
328
315
 
316
+ private static byte[] readBytesWithLimit(InputStream in) throws IOException {
317
+ byte[] buffer = new byte[10240];
318
+ ByteArrayOutputStream output = new ByteArrayOutputStream();
319
+ int read;
320
+
321
+ while ((read = in.read(buffer)) != -1) {
322
+ output.write(buffer, 0, read);
323
+ }
324
+
325
+ return output.toByteArray();
326
+ }
327
+
329
328
  /**
330
329
  * Static method that returns system folders to JS context
331
330
  *
@@ -217,7 +217,7 @@ public class ReactNativeBlobUtilReq extends BroadcastReceiver implements Runnabl
217
217
  cursor.close();
218
218
 
219
219
  ReactNativeBlobUtilProgressConfig reportConfig = getReportProgress(taskId);
220
- float progress = (total > 0) ? written / total : 0;
220
+ float progress = (total > 0) ? (float) written / total : 0;
221
221
 
222
222
  if (reportConfig != null && reportConfig.shouldReport(progress /* progress */)) {
223
223
  WritableMap args = Arguments.createMap();
@@ -617,6 +617,14 @@ public class ReactNativeBlobUtilReq extends BroadcastReceiver implements Runnabl
617
617
 
618
618
  if (options.timeout >= 0) {
619
619
  clientBuilder.connectTimeout(options.timeout, TimeUnit.MILLISECONDS);
620
+ }
621
+ // For file-to-disk downloads use no read timeout: the 60-second default
622
+ // can fire on slow connections before a large file finishes transferring.
623
+ // Individual socket reads on a healthy connection take milliseconds, so
624
+ // there is no risk of hanging indefinitely; the user can always cancel().
625
+ if (responseType == ResponseType.FileStorage) {
626
+ clientBuilder.readTimeout(0, TimeUnit.MILLISECONDS);
627
+ } else if (options.timeout >= 0) {
620
628
  clientBuilder.readTimeout(options.timeout, TimeUnit.MILLISECONDS);
621
629
  }
622
630
 
@@ -781,11 +789,18 @@ public class ReactNativeBlobUtilReq extends BroadcastReceiver implements Runnabl
781
789
  case FileStorage:
782
790
  ResponseBody responseBody = resp.body();
783
791
 
792
+ // Drain via byteStream() — avoids OkHttp's bytes() check that rejects
793
+ // content-length > Integer.MAX_VALUE (2 GB). ProgressReportingSource.read()
794
+ // writes each chunk to disk as a side-effect. Closing the stream flushes
795
+ // and closes the FileOutputStream that holds the destination file.
784
796
  try {
785
- // In order to write response data to `destPath` we have to invoke this method.
786
- // It uses customized response body which is able to report download progress
787
- // and write response data to destination path.
788
- responseBody.bytes();
797
+ java.io.InputStream drainStream = responseBody.byteStream();
798
+ try {
799
+ byte[] drainBuf = new byte[65536];
800
+ while (drainStream.read(drainBuf) != -1) { }
801
+ } finally {
802
+ try { drainStream.close(); } catch (Exception ignored2) { }
803
+ }
789
804
  } catch (Exception ignored) {
790
805
  // ignored.printStackTrace();
791
806
  }
@@ -67,7 +67,7 @@ public class ReactNativeBlobUtilDefaultResp extends ResponseBody {
67
67
  bytesRead += read > 0 ? read : 0;
68
68
  ReactNativeBlobUtilProgressConfig reportConfig = ReactNativeBlobUtilReq.getReportProgress(mTaskId);
69
69
  long cLen = contentLength();
70
- if (reportConfig != null && cLen != 0 && reportConfig.shouldReport(bytesRead / contentLength())) {
70
+ if (reportConfig != null && cLen != 0 && reportConfig.shouldReport(cLen > 0 ? (float) bytesRead / cLen : 0)) {
71
71
  WritableMap args = Arguments.createMap();
72
72
  args.putString("taskId", mTaskId);
73
73
  args.putString("written", String.valueOf(bytesRead));
@@ -123,6 +123,11 @@ public class ReactNativeBlobUtilFileResp extends ResponseBody {
123
123
  bytesDownloaded += read > 0 ? read : 0;
124
124
  if (read > 0) {
125
125
  ofStream.write(bytes, 0, (int) read);
126
+ // Forward bytes into the Okio sink too. Without this the buffer
127
+ // stays empty and buffered consumers (byteStream()/source().read())
128
+ // hit a false EOF after the first 8 KB segment, so any file larger
129
+ // than one segment fails with "Download interrupted." (0.24.10 regression).
130
+ sink.write(bytes, 0, (int) read);
126
131
  } else if (contentLength() == -1 && read == -1) {
127
132
  // End marker has been received for chunked download
128
133
  isEndMarkerReceived = true;
@@ -133,7 +138,7 @@ public class ReactNativeBlobUtilFileResp extends ResponseBody {
133
138
 
134
139
  // For non-chunked download, progress is received / total
135
140
  // For chunked download, progress can be either 0 (started) or 1 (ended)
136
- float progress = (contentLength() != -1) ? bytesDownloaded / contentLength() : ((isEndMarkerReceived) ? 1 : 0);
141
+ float progress = (contentLength() != -1) ? (float) bytesDownloaded / contentLength() : ((isEndMarkerReceived) ? 1 : 0);
137
142
 
138
143
  if (reportConfig != null && reportConfig.shouldReport(progress /* progress */)) {
139
144
  if (contentLength() != -1) {