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.
- package/.claude/settings.local.json +9 -0
- package/android/build.gradle +2 -2
- package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilFS.java +26 -27
- package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilReq.java +20 -5
- package/android/src/main/java/com/ReactNativeBlobUtil/Response/ReactNativeBlobUtilDefaultResp.java +1 -1
- package/android/src/main/java/com/ReactNativeBlobUtil/Response/ReactNativeBlobUtilFileResp.java +6 -1
- package/fetch.js +351 -350
- package/index.d.ts +2 -2
- package/index.js.flow +192 -192
- package/ios/ReactNativeBlobUtilRequest.mm +78 -2
- package/package.json +83 -85
- package/utils/byteCount.js +20 -0
- package/utils/uuid.js +11 -11
package/android/build.gradle
CHANGED
|
@@ -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
|
-
|
|
260
|
-
|
|
261
|
-
|
|
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
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
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
|
-
|
|
280
|
-
|
|
281
|
-
|
|
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
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
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
|
}
|
package/android/src/main/java/com/ReactNativeBlobUtil/Response/ReactNativeBlobUtilDefaultResp.java
CHANGED
|
@@ -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 /
|
|
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));
|
package/android/src/main/java/com/ReactNativeBlobUtil/Response/ReactNativeBlobUtilFileResp.java
CHANGED
|
@@ -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) {
|