react-native-blob-util 0.13.18 → 0.15.0
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/README.md +542 -401
- package/android/build.gradle +1 -0
- package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtil.java +89 -25
- package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilBody.java +14 -15
- package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilConfig.java +10 -6
- package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilFS.java +115 -289
- package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilFileTransformer.java +10 -0
- package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilMediaCollection.java +314 -0
- package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilPackage.java +6 -2
- package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilReq.java +46 -22
- package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilStream.java +287 -0
- package/android/src/main/java/com/ReactNativeBlobUtil/ReactNativeBlobUtilUtils.java +57 -2
- package/android/src/main/java/com/ReactNativeBlobUtil/Response/ReactNativeBlobUtilFileResp.java +9 -0
- package/android/src/main/java/com/ReactNativeBlobUtil/Utils/FileDescription.java +19 -0
- package/android/src/main/java/com/ReactNativeBlobUtil/Utils/MimeType.java +70 -0
- package/class/ReactNativeBlobUtilBlobResponse.js +1 -1
- package/fs.js +44 -4
- package/index.d.ts +121 -1
- package/index.js +2 -0
- package/ios/ReactNativeBlobUtil/ReactNativeBlobUtil.m +6 -4
- package/ios/ReactNativeBlobUtil.xcodeproj/project.pbxproj +6 -0
- package/ios/ReactNativeBlobUtilConst.h +1 -0
- package/ios/ReactNativeBlobUtilConst.m +1 -0
- package/ios/ReactNativeBlobUtilFS.h +3 -1
- package/ios/ReactNativeBlobUtilFS.m +33 -0
- package/ios/ReactNativeBlobUtilFileTransformer.h +24 -0
- package/ios/ReactNativeBlobUtilFileTransformer.m +21 -0
- package/ios/ReactNativeBlobUtilReqBuilder.m +2 -2
- package/ios/ReactNativeBlobUtilRequest.m +30 -1
- package/mediacollection.js +38 -0
- package/package.json +1 -1
- package/polyfill/Fetch.js +4 -2
- package/scripts/prelink.js +1 -1
- package/types.js +4 -0
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
package com.ReactNativeBlobUtil;
|
|
2
|
+
|
|
3
|
+
import android.content.ContentResolver;
|
|
4
|
+
import android.content.ContentValues;
|
|
5
|
+
import android.content.Context;
|
|
6
|
+
import android.net.Uri;
|
|
7
|
+
import android.os.Build;
|
|
8
|
+
import android.os.Environment;
|
|
9
|
+
import android.os.ParcelFileDescriptor;
|
|
10
|
+
import android.provider.MediaStore;
|
|
11
|
+
import android.util.Base64;
|
|
12
|
+
|
|
13
|
+
import com.ReactNativeBlobUtil.Utils.FileDescription;
|
|
14
|
+
import com.facebook.react.bridge.Arguments;
|
|
15
|
+
import com.facebook.react.bridge.Promise;
|
|
16
|
+
import com.facebook.react.bridge.ReactApplicationContext;
|
|
17
|
+
import com.facebook.react.bridge.WritableArray;
|
|
18
|
+
|
|
19
|
+
import java.io.File;
|
|
20
|
+
import java.io.FileInputStream;
|
|
21
|
+
import java.io.FileOutputStream;
|
|
22
|
+
import java.io.IOException;
|
|
23
|
+
import java.io.InputStream;
|
|
24
|
+
import java.io.OutputStream;
|
|
25
|
+
|
|
26
|
+
public class ReactNativeBlobUtilMediaCollection {
|
|
27
|
+
|
|
28
|
+
public enum MediaType {
|
|
29
|
+
Audio,
|
|
30
|
+
Image,
|
|
31
|
+
Video,
|
|
32
|
+
Download
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
private static Uri getMediaUri(MediaType mt) {
|
|
36
|
+
Uri res = null;
|
|
37
|
+
if (mt == MediaType.Audio) {
|
|
38
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
|
39
|
+
res = MediaStore.Audio.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY);
|
|
40
|
+
} else {
|
|
41
|
+
res = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
|
|
42
|
+
}
|
|
43
|
+
} else if (mt == MediaType.Video) {
|
|
44
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
|
45
|
+
res = MediaStore.Video.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY);
|
|
46
|
+
} else {
|
|
47
|
+
res = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
|
|
48
|
+
}
|
|
49
|
+
} else if (mt == MediaType.Image) {
|
|
50
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
|
51
|
+
res = MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY);
|
|
52
|
+
} else {
|
|
53
|
+
res = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
|
|
54
|
+
}
|
|
55
|
+
} else if (mt == MediaType.Download) {
|
|
56
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
|
57
|
+
res = MediaStore.Downloads.getContentUri(MediaStore.VOLUME_EXTERNAL_PRIMARY);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return res;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
private static String getRelativePath(MediaType mt, ReactApplicationContext ctx) {
|
|
65
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
|
66
|
+
if (mt == MediaType.Audio) return Environment.DIRECTORY_MUSIC;
|
|
67
|
+
if (mt == MediaType.Video) return Environment.DIRECTORY_MOVIES;
|
|
68
|
+
if (mt == MediaType.Image) return Environment.DIRECTORY_PICTURES;
|
|
69
|
+
if (mt == MediaType.Download) return Environment.DIRECTORY_DOWNLOADS;
|
|
70
|
+
return Environment.DIRECTORY_DOWNLOADS;
|
|
71
|
+
} else {
|
|
72
|
+
if (mt == MediaType.Audio) return ReactNativeBlobUtilFS.getExternalFilesDirPath(ctx, Environment.DIRECTORY_MUSIC);
|
|
73
|
+
if (mt == MediaType.Video) return ReactNativeBlobUtilFS.getExternalFilesDirPath(ctx, Environment.DIRECTORY_MOVIES);
|
|
74
|
+
if (mt == MediaType.Image) return ReactNativeBlobUtilFS.getExternalFilesDirPath(ctx, Environment.DIRECTORY_PICTURES);
|
|
75
|
+
if (mt == MediaType.Download) return ReactNativeBlobUtilFS.getExternalFilesDirPath(ctx, Environment.DIRECTORY_DOWNLOADS);
|
|
76
|
+
return ReactNativeBlobUtilFS.getExternalFilesDirPath(ctx, Environment.DIRECTORY_DOWNLOADS);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
public static Uri createNewMediaFile(FileDescription file, MediaType mt, ReactApplicationContext ctx) {
|
|
81
|
+
// Add a specific media item.
|
|
82
|
+
Context appCtx = ReactNativeBlobUtil.RCTContext.getApplicationContext();
|
|
83
|
+
ContentResolver resolver = appCtx.getContentResolver();
|
|
84
|
+
|
|
85
|
+
ContentValues fileDetails = new ContentValues();
|
|
86
|
+
String relativePath = getRelativePath(mt, ctx);
|
|
87
|
+
String mimeType = file.mimeType;
|
|
88
|
+
|
|
89
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
|
90
|
+
fileDetails.put(MediaStore.MediaColumns.DATE_ADDED, System.currentTimeMillis() / 1000);
|
|
91
|
+
fileDetails.put(MediaStore.MediaColumns.DATE_MODIFIED, System.currentTimeMillis() / 1000);
|
|
92
|
+
fileDetails.put(MediaStore.MediaColumns.MIME_TYPE, mimeType);
|
|
93
|
+
fileDetails.put(MediaStore.MediaColumns.DISPLAY_NAME, file.name);
|
|
94
|
+
fileDetails.put(MediaStore.MediaColumns.RELATIVE_PATH, relativePath + '/' + file.partentFolder);
|
|
95
|
+
|
|
96
|
+
Uri mediauri = getMediaUri(mt);
|
|
97
|
+
|
|
98
|
+
// Keeps a handle to the new file's URI in case we need to modify it later.
|
|
99
|
+
return resolver.insert(mediauri, fileDetails);
|
|
100
|
+
} else {
|
|
101
|
+
File f = new File(relativePath + file.getFullPath());
|
|
102
|
+
if (true) {
|
|
103
|
+
if (!f.exists()) {
|
|
104
|
+
File parent = f.getParentFile();
|
|
105
|
+
if (parent != null && !parent.exists() && !parent.mkdirs()) {
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
try {
|
|
109
|
+
if (f.createNewFile()) ;
|
|
110
|
+
{
|
|
111
|
+
return Uri.fromFile(f);
|
|
112
|
+
}
|
|
113
|
+
} catch (IOException ioException) {
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
} else {
|
|
118
|
+
return Uri.fromFile(f);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
public static boolean writeToMediaFile(Uri fileUri, String data, boolean transformFile, Promise promise) {
|
|
128
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
|
129
|
+
try {
|
|
130
|
+
Context appCtx = ReactNativeBlobUtil.RCTContext.getApplicationContext();
|
|
131
|
+
ContentResolver resolver = appCtx.getContentResolver();
|
|
132
|
+
|
|
133
|
+
// set pending doesn't work right now. We would have to requery for the item
|
|
134
|
+
//ContentValues contentValues = new ContentValues();
|
|
135
|
+
//contentValues.put(MediaStore.MediaColumns.IS_PENDING, 1);
|
|
136
|
+
//resolver.update(fileUri, contentValues, null, null);
|
|
137
|
+
|
|
138
|
+
// write data
|
|
139
|
+
OutputStream stream = null;
|
|
140
|
+
Uri uri = null;
|
|
141
|
+
|
|
142
|
+
try {
|
|
143
|
+
ParcelFileDescriptor descr;
|
|
144
|
+
try {
|
|
145
|
+
assert fileUri != null;
|
|
146
|
+
descr = appCtx.getContentResolver().openFileDescriptor(fileUri, "w");
|
|
147
|
+
assert descr != null;
|
|
148
|
+
String normalizedData = ReactNativeBlobUtilUtils.normalizePath(data);
|
|
149
|
+
File src = new File(normalizedData);
|
|
150
|
+
if (!src.exists()) {
|
|
151
|
+
promise.reject("ENOENT", "No such file ('" + normalizedData + "')");
|
|
152
|
+
return false;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
FileInputStream fin = new FileInputStream(src);
|
|
157
|
+
FileOutputStream out = new FileOutputStream(descr.getFileDescriptor());
|
|
158
|
+
|
|
159
|
+
if (transformFile) {
|
|
160
|
+
// in order to transform file, we must load the entire file onto memory
|
|
161
|
+
int length = (int) src.length();
|
|
162
|
+
byte[] bytes = new byte[length];
|
|
163
|
+
fin.read(bytes);
|
|
164
|
+
if (ReactNativeBlobUtilFileTransformer.sharedFileTransformer == null) {
|
|
165
|
+
throw new IllegalStateException("Write to media file with transform was specified but the shared file transformer is not set");
|
|
166
|
+
}
|
|
167
|
+
byte[] transformedBytes = ReactNativeBlobUtilFileTransformer.sharedFileTransformer.onWriteFile(bytes);
|
|
168
|
+
out.write(transformedBytes);
|
|
169
|
+
} else {
|
|
170
|
+
byte[] buf = new byte[10240];
|
|
171
|
+
int read;
|
|
172
|
+
|
|
173
|
+
while ((read = fin.read(buf)) > 0) {
|
|
174
|
+
out.write(buf, 0, read);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
fin.close();
|
|
180
|
+
out.close();
|
|
181
|
+
descr.close();
|
|
182
|
+
} catch (Exception e) {
|
|
183
|
+
e.printStackTrace();
|
|
184
|
+
promise.reject(new IOException("Failed to get output stream."));
|
|
185
|
+
return false;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
//contentValues.clear();
|
|
189
|
+
//contentValues.put(MediaStore.Video.Media.IS_PENDING, 0);
|
|
190
|
+
//appCtx.getContentResolver().update(fileUri, contentValues, null, null);
|
|
191
|
+
stream = resolver.openOutputStream(fileUri);
|
|
192
|
+
if (stream == null) {
|
|
193
|
+
promise.reject(new IOException("Failed to get output stream."));
|
|
194
|
+
return false;
|
|
195
|
+
}
|
|
196
|
+
} catch (IOException e) {
|
|
197
|
+
// Don't leave an orphan entry in the MediaStore
|
|
198
|
+
resolver.delete(uri, null, null);
|
|
199
|
+
promise.reject(e);
|
|
200
|
+
return false;
|
|
201
|
+
} finally {
|
|
202
|
+
if (stream != null) {
|
|
203
|
+
stream.close();
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// remove pending
|
|
208
|
+
//contentValues = new ContentValues();
|
|
209
|
+
//contentValues.put(MediaStore.MediaColumns.IS_PENDING, 0);
|
|
210
|
+
//resolver.update(fileUri, contentValues, null, null);
|
|
211
|
+
|
|
212
|
+
} catch (IOException e) {
|
|
213
|
+
promise.reject("ReactNativeBlobUtil.createMediaFile", "Cannot write to file, file might not exist");
|
|
214
|
+
return false;
|
|
215
|
+
}
|
|
216
|
+
return true;
|
|
217
|
+
} else {
|
|
218
|
+
return ReactNativeBlobUtilFS.writeFile(ReactNativeBlobUtilUtils.normalizePath(fileUri.toString()), ReactNativeBlobUtilConst.DATA_ENCODE_URI, data, false);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
public static void copyToInternal(Uri contenturi, String destpath, Promise promise) {
|
|
223
|
+
Context appCtx = ReactNativeBlobUtil.RCTContext.getApplicationContext();
|
|
224
|
+
ContentResolver resolver = appCtx.getContentResolver();
|
|
225
|
+
|
|
226
|
+
InputStream in = null;
|
|
227
|
+
OutputStream out = null;
|
|
228
|
+
File f = new File((destpath));
|
|
229
|
+
|
|
230
|
+
if (!f.exists()) {
|
|
231
|
+
try {
|
|
232
|
+
File parent = f.getParentFile();
|
|
233
|
+
if (parent != null && !parent.exists() && !parent.mkdirs()) {
|
|
234
|
+
promise.reject("ReactNativeBlobUtil.copyToInternal: Cannot create parent folders<'" + destpath);
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
boolean result = f.createNewFile();
|
|
238
|
+
if (!result) {
|
|
239
|
+
promise.reject("ReactNativeBlobUtil.copyToInternal: Destination file at '" + destpath + "' already exists");
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
} catch (IOException ioException) {
|
|
243
|
+
promise.reject("ReactNativeBlobUtil.copyToInternal: Could not create file: " + ioException.getLocalizedMessage());
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
try {
|
|
248
|
+
in = resolver.openInputStream(contenturi);
|
|
249
|
+
out = new FileOutputStream(destpath);
|
|
250
|
+
|
|
251
|
+
byte[] buf = new byte[10240];
|
|
252
|
+
int len;
|
|
253
|
+
while ((len = in.read(buf)) > 0) {
|
|
254
|
+
out.write(buf, 0, len);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
} catch (IOException e) {
|
|
258
|
+
promise.reject("ReactNativeBlobUtil.copyToInternal: Could not write data: " + e.getLocalizedMessage());
|
|
259
|
+
} finally {
|
|
260
|
+
if (in != null) {
|
|
261
|
+
try {
|
|
262
|
+
in.close();
|
|
263
|
+
} catch (IOException ioException) {
|
|
264
|
+
ioException.printStackTrace();
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
if (out != null) {
|
|
268
|
+
try {
|
|
269
|
+
out.close();
|
|
270
|
+
} catch (IOException ioException) {
|
|
271
|
+
ioException.printStackTrace();
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
promise.resolve("");
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
public static void getBlob(Uri contentUri, String encoding, Promise promise) {
|
|
280
|
+
Context appCtx = ReactNativeBlobUtil.RCTContext.getApplicationContext();
|
|
281
|
+
ContentResolver resolver = appCtx.getContentResolver();
|
|
282
|
+
try {
|
|
283
|
+
InputStream in = resolver.openInputStream(contentUri);
|
|
284
|
+
int length = in.available();
|
|
285
|
+
|
|
286
|
+
byte[] bytes = new byte[length];
|
|
287
|
+
int bytesRead = in.read(bytes);
|
|
288
|
+
in.close();
|
|
289
|
+
|
|
290
|
+
if (bytesRead < length) {
|
|
291
|
+
promise.reject("EUNSPECIFIED", "Read only " + bytesRead + " bytes of " + length);
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
switch (encoding.toLowerCase()) {
|
|
296
|
+
case "base64":
|
|
297
|
+
promise.resolve(Base64.encodeToString(bytes, Base64.NO_WRAP));
|
|
298
|
+
break;
|
|
299
|
+
case "ascii":
|
|
300
|
+
WritableArray asciiResult = Arguments.createArray();
|
|
301
|
+
for (byte b : bytes) {
|
|
302
|
+
asciiResult.pushInt(b);
|
|
303
|
+
}
|
|
304
|
+
promise.resolve(asciiResult);
|
|
305
|
+
break;
|
|
306
|
+
default: // covers utf-8
|
|
307
|
+
promise.resolve(new String(bytes));
|
|
308
|
+
break;
|
|
309
|
+
}
|
|
310
|
+
} catch (IOException ioException) {
|
|
311
|
+
ioException.printStackTrace();
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
package com.ReactNativeBlobUtil;
|
|
2
2
|
|
|
3
|
+
import androidx.annotation.NonNull;
|
|
4
|
+
|
|
3
5
|
import com.facebook.react.ReactPackage;
|
|
4
6
|
import com.facebook.react.bridge.JavaScriptModule;
|
|
5
7
|
import com.facebook.react.bridge.NativeModule;
|
|
@@ -13,8 +15,9 @@ import java.util.List;
|
|
|
13
15
|
|
|
14
16
|
public class ReactNativeBlobUtilPackage implements ReactPackage {
|
|
15
17
|
|
|
18
|
+
@NonNull
|
|
16
19
|
@Override
|
|
17
|
-
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
|
|
20
|
+
public List<NativeModule> createNativeModules(@NonNull ReactApplicationContext reactContext) {
|
|
18
21
|
List<NativeModule> modules = new ArrayList<>();
|
|
19
22
|
modules.add(new ReactNativeBlobUtil(reactContext));
|
|
20
23
|
return modules;
|
|
@@ -24,8 +27,9 @@ public class ReactNativeBlobUtilPackage implements ReactPackage {
|
|
|
24
27
|
return Collections.emptyList();
|
|
25
28
|
}
|
|
26
29
|
|
|
30
|
+
@NonNull
|
|
27
31
|
@Override
|
|
28
|
-
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
|
|
32
|
+
public List<ViewManager> createViewManagers(@NonNull ReactApplicationContext reactContext) {
|
|
29
33
|
return Collections.emptyList();
|
|
30
34
|
}
|
|
31
35
|
|
|
@@ -30,33 +30,27 @@ import com.facebook.react.bridge.WritableArray;
|
|
|
30
30
|
import com.facebook.react.bridge.WritableMap;
|
|
31
31
|
import com.facebook.react.modules.core.DeviceEventManagerModule;
|
|
32
32
|
|
|
33
|
-
import javax.net.ssl.TrustManagerFactory;
|
|
34
|
-
import javax.net.ssl.TrustManager;
|
|
35
|
-
import javax.net.ssl.X509TrustManager;
|
|
36
|
-
import javax.net.ssl.SSLContext;
|
|
37
|
-
|
|
38
33
|
import java.io.File;
|
|
39
34
|
import java.io.FileOutputStream;
|
|
40
35
|
import java.io.IOException;
|
|
41
36
|
import java.io.InputStream;
|
|
42
37
|
import java.net.MalformedURLException;
|
|
38
|
+
import java.net.Proxy;
|
|
43
39
|
import java.net.SocketException;
|
|
44
40
|
import java.net.SocketTimeoutException;
|
|
45
41
|
import java.net.URL;
|
|
46
|
-
import java.net.Proxy;
|
|
47
42
|
import java.nio.ByteBuffer;
|
|
48
43
|
import java.nio.charset.CharacterCodingException;
|
|
49
44
|
import java.nio.charset.Charset;
|
|
50
45
|
import java.nio.charset.CharsetDecoder;
|
|
51
|
-
import java.security.KeyStore;
|
|
52
46
|
import java.util.ArrayList;
|
|
53
|
-
import java.util.Arrays;
|
|
54
|
-
import java.util.List;
|
|
55
47
|
import java.util.HashMap;
|
|
56
48
|
|
|
49
|
+
import java.util.List;
|
|
50
|
+
import java.util.Locale;
|
|
57
51
|
import java.util.concurrent.TimeUnit;
|
|
58
52
|
|
|
59
|
-
import javax.net.ssl.
|
|
53
|
+
import javax.net.ssl.SSLContext;
|
|
60
54
|
|
|
61
55
|
import okhttp3.Call;
|
|
62
56
|
import okhttp3.ConnectionPool;
|
|
@@ -93,6 +87,12 @@ public class ReactNativeBlobUtilReq extends BroadcastReceiver implements Runnabl
|
|
|
93
87
|
BASE64
|
|
94
88
|
}
|
|
95
89
|
|
|
90
|
+
private boolean shouldTransformFile() {
|
|
91
|
+
return this.options.transformFile &&
|
|
92
|
+
// Can only process if it's written to a file
|
|
93
|
+
(this.options.fileCache || this.options.path != null);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
96
|
public static HashMap<String, Call> taskTable = new HashMap<>();
|
|
97
97
|
public static HashMap<String, Long> androidDownloadManagerTaskTable = new HashMap<>();
|
|
98
98
|
static HashMap<String, ReactNativeBlobUtilProgressConfig> progressReport = new HashMap<>();
|
|
@@ -120,7 +120,7 @@ public class ReactNativeBlobUtilReq extends BroadcastReceiver implements Runnabl
|
|
|
120
120
|
OkHttpClient client;
|
|
121
121
|
|
|
122
122
|
public ReactNativeBlobUtilReq(ReadableMap options, String taskId, String method, String url, ReadableMap headers, String body, ReadableArray arrayBody, OkHttpClient client, final Callback callback) {
|
|
123
|
-
this.method = method.toUpperCase();
|
|
123
|
+
this.method = method.toUpperCase(Locale.ROOT);
|
|
124
124
|
this.options = new ReactNativeBlobUtilConfig(options);
|
|
125
125
|
this.taskId = taskId;
|
|
126
126
|
this.url = url;
|
|
@@ -130,7 +130,9 @@ public class ReactNativeBlobUtilReq extends BroadcastReceiver implements Runnabl
|
|
|
130
130
|
this.rawRequestBodyArray = arrayBody;
|
|
131
131
|
this.client = client;
|
|
132
132
|
|
|
133
|
-
|
|
133
|
+
// If transformFile is specified, we first want to get the response back in memory so we can
|
|
134
|
+
// encrypt it wholesale and at that point, write it into the file storage.
|
|
135
|
+
if((this.options.fileCache || this.options.path != null) && !this.shouldTransformFile())
|
|
134
136
|
responseType = ResponseType.FileStorage;
|
|
135
137
|
else
|
|
136
138
|
responseType = ResponseType.KeepInMemory;
|
|
@@ -196,7 +198,7 @@ public class ReactNativeBlobUtilReq extends BroadcastReceiver implements Runnabl
|
|
|
196
198
|
req.addRequestHeader(key, headers.getString(key));
|
|
197
199
|
}
|
|
198
200
|
// Attempt to add cookie, if it exists
|
|
199
|
-
URL urlObj
|
|
201
|
+
URL urlObj;
|
|
200
202
|
try {
|
|
201
203
|
urlObj = new URL(url);
|
|
202
204
|
String baseUrl = urlObj.getProtocol() + "://" + urlObj.getHost();
|
|
@@ -311,14 +313,14 @@ public class ReactNativeBlobUtilReq extends BroadcastReceiver implements Runnabl
|
|
|
311
313
|
else if (value.equalsIgnoreCase("utf8"))
|
|
312
314
|
responseFormat = ResponseFormat.UTF8;
|
|
313
315
|
} else {
|
|
314
|
-
builder.header(key.toLowerCase(), value);
|
|
315
|
-
mheaders.put(key.toLowerCase(), value);
|
|
316
|
+
builder.header(key.toLowerCase(Locale.ROOT), value);
|
|
317
|
+
mheaders.put(key.toLowerCase(Locale.ROOT), value);
|
|
316
318
|
}
|
|
317
319
|
}
|
|
318
320
|
}
|
|
319
321
|
|
|
320
322
|
if (method.equalsIgnoreCase("post") || method.equalsIgnoreCase("put") || method.equalsIgnoreCase("patch")) {
|
|
321
|
-
String cType = getHeaderIgnoreCases(mheaders, "Content-Type").toLowerCase();
|
|
323
|
+
String cType = getHeaderIgnoreCases(mheaders, "Content-Type").toLowerCase(Locale.ROOT);
|
|
322
324
|
|
|
323
325
|
if (rawRequestBodyArray != null) {
|
|
324
326
|
requestType = RequestType.Form;
|
|
@@ -332,7 +334,7 @@ public class ReactNativeBlobUtilReq extends BroadcastReceiver implements Runnabl
|
|
|
332
334
|
if (rawRequestBody.startsWith(ReactNativeBlobUtilConst.FILE_PREFIX)
|
|
333
335
|
|| rawRequestBody.startsWith(ReactNativeBlobUtilConst.CONTENT_PREFIX)) {
|
|
334
336
|
requestType = RequestType.SingleFile;
|
|
335
|
-
} else if (cType.toLowerCase().contains(";base64") || cType.toLowerCase().startsWith("application/octet")) {
|
|
337
|
+
} else if (cType.toLowerCase(Locale.ROOT).contains(";base64") || cType.toLowerCase(Locale.ROOT).startsWith("application/octet")) {
|
|
336
338
|
cType = cType.replace(";base64", "").replace(";BASE64", "");
|
|
337
339
|
if (mheaders.containsKey("content-type"))
|
|
338
340
|
mheaders.put("content-type", cType);
|
|
@@ -388,14 +390,16 @@ public class ReactNativeBlobUtilReq extends BroadcastReceiver implements Runnabl
|
|
|
388
390
|
// #156 fix cookie issue
|
|
389
391
|
final Request req = builder.build();
|
|
390
392
|
clientBuilder.addNetworkInterceptor(new Interceptor() {
|
|
393
|
+
@NonNull
|
|
391
394
|
@Override
|
|
392
|
-
public Response intercept(Chain chain) throws IOException {
|
|
395
|
+
public Response intercept(@NonNull Chain chain) throws IOException {
|
|
393
396
|
redirects.add(chain.request().url().toString());
|
|
394
397
|
return chain.proceed(chain.request());
|
|
395
398
|
}
|
|
396
399
|
});
|
|
397
400
|
// Add request interceptor for upload progress event
|
|
398
401
|
clientBuilder.addInterceptor(new Interceptor() {
|
|
402
|
+
@NonNull
|
|
399
403
|
@Override
|
|
400
404
|
public Response intercept(@NonNull Chain chain) throws IOException {
|
|
401
405
|
Response originalResponse = null;
|
|
@@ -467,7 +471,7 @@ public class ReactNativeBlobUtilReq extends BroadcastReceiver implements Runnabl
|
|
|
467
471
|
call.enqueue(new okhttp3.Callback() {
|
|
468
472
|
|
|
469
473
|
@Override
|
|
470
|
-
public void onFailure(@NonNull Call call, IOException e) {
|
|
474
|
+
public void onFailure(@NonNull Call call, @NonNull IOException e) {
|
|
471
475
|
cancelTask(taskId);
|
|
472
476
|
if (respInfo == null) {
|
|
473
477
|
respInfo = Arguments.createMap();
|
|
@@ -561,6 +565,26 @@ public class ReactNativeBlobUtilReq extends BroadcastReceiver implements Runnabl
|
|
|
561
565
|
// response data directly pass to JS context as string.
|
|
562
566
|
else {
|
|
563
567
|
byte[] b = resp.body().bytes();
|
|
568
|
+
// If process file option is turned on, we first keep response in memory and then stream that content
|
|
569
|
+
// after processing
|
|
570
|
+
if (this.shouldTransformFile()) {
|
|
571
|
+
if (ReactNativeBlobUtilFileTransformer.sharedFileTransformer == null) {
|
|
572
|
+
throw new IllegalStateException("Write file with transform was specified but the shared file transformer is not set");
|
|
573
|
+
}
|
|
574
|
+
this.destPath = this.destPath.replace("?append=true", "");
|
|
575
|
+
File file = new File(this.destPath);
|
|
576
|
+
if (!file.exists()) {
|
|
577
|
+
file.createNewFile();
|
|
578
|
+
}
|
|
579
|
+
try (FileOutputStream fos = new FileOutputStream(file)) {
|
|
580
|
+
fos.write(ReactNativeBlobUtilFileTransformer.sharedFileTransformer.onWriteFile(b));
|
|
581
|
+
} catch(Exception e) {
|
|
582
|
+
callback.invoke("Error from file transformer:" + e.getLocalizedMessage(), null);
|
|
583
|
+
return;
|
|
584
|
+
}
|
|
585
|
+
callback.invoke(null, ReactNativeBlobUtilConst.RNFB_RESPONSE_PATH, this.destPath);
|
|
586
|
+
return;
|
|
587
|
+
}
|
|
564
588
|
if (responseFormat == ResponseFormat.BASE64) {
|
|
565
589
|
callback.invoke(null, ReactNativeBlobUtilConst.RNFB_RESPONSE_BASE64, android.util.Base64.encodeToString(b, Base64.NO_WRAP));
|
|
566
590
|
return;
|
|
@@ -718,7 +742,7 @@ public class ReactNativeBlobUtilReq extends BroadcastReceiver implements Runnabl
|
|
|
718
742
|
boolean isCustomBinary = false;
|
|
719
743
|
if (options.binaryContentTypes != null) {
|
|
720
744
|
for (int i = 0; i < options.binaryContentTypes.size(); i++) {
|
|
721
|
-
if (ctype.toLowerCase().contains(options.binaryContentTypes.getString(i).toLowerCase())) {
|
|
745
|
+
if (ctype.toLowerCase(Locale.ROOT).contains(options.binaryContentTypes.getString(i).toLowerCase(Locale.ROOT))) {
|
|
722
746
|
isCustomBinary = true;
|
|
723
747
|
break;
|
|
724
748
|
}
|
|
@@ -730,13 +754,13 @@ public class ReactNativeBlobUtilReq extends BroadcastReceiver implements Runnabl
|
|
|
730
754
|
private String getHeaderIgnoreCases(Headers headers, String field) {
|
|
731
755
|
String val = headers.get(field);
|
|
732
756
|
if (val != null) return val;
|
|
733
|
-
return headers.get(field.toLowerCase()) == null ? "" : headers.get(field.toLowerCase());
|
|
757
|
+
return headers.get(field.toLowerCase(Locale.ROOT)) == null ? "" : headers.get(field.toLowerCase(Locale.ROOT));
|
|
734
758
|
}
|
|
735
759
|
|
|
736
760
|
private String getHeaderIgnoreCases(HashMap<String, String> headers, String field) {
|
|
737
761
|
String val = headers.get(field);
|
|
738
762
|
if (val != null) return val;
|
|
739
|
-
String lowerCasedValue = headers.get(field.toLowerCase());
|
|
763
|
+
String lowerCasedValue = headers.get(field.toLowerCase(Locale.ROOT));
|
|
740
764
|
return lowerCasedValue == null ? "" : lowerCasedValue;
|
|
741
765
|
}
|
|
742
766
|
|