Skip to content
This repository was archived by the owner on Mar 16, 2019. It is now read-only.

Commit deb1b58

Browse files
committedAug 18, 2016
Add Android fixed length request implementation #94
1 parent e23292f commit deb1b58

File tree

4 files changed

+121
-76
lines changed

4 files changed

+121
-76
lines changed
 

‎src/android/src/main/java/com/RNFetchBlob/RNFetchBlobBody.java

+100-73
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,12 @@
1313
import java.io.ByteArrayInputStream;
1414
import java.io.File;
1515
import java.io.FileInputStream;
16+
import java.io.FileNotFoundException;
17+
import java.io.FileOutputStream;
1618
import java.io.IOException;
1719
import java.io.InputStream;
20+
import java.nio.ByteBuffer;
21+
import java.nio.MappedByteBuffer;
1822
import java.util.ArrayList;
1923
import java.util.HashMap;
2024

@@ -33,19 +37,27 @@
3337
public class RNFetchBlobBody extends RequestBody{
3438

3539
InputStream requestStream;
36-
long contentLength;
40+
long contentLength = 0;
3741
long bytesWritten = 0;
3842
ReadableArray form;
3943
String mTaskId;
4044
String rawBody;
4145
RNFetchBlobReq.RequestType requestType;
4246
MediaType mime;
47+
File bodyCache;
48+
4349

4450
public RNFetchBlobBody(String taskId, RNFetchBlobReq.RequestType type, ReadableArray form, MediaType contentType) {
4551
this.mTaskId = taskId;
4652
this.form = form;
4753
requestType = type;
4854
mime = contentType;
55+
try {
56+
bodyCache = createMultipartBodyCache();
57+
contentLength = bodyCache.length();
58+
} catch (IOException e) {
59+
e.printStackTrace();
60+
}
4961
}
5062

5163
public RNFetchBlobBody(String taskId, RNFetchBlobReq.RequestType type, String rawBody, MediaType contentType) {
@@ -55,6 +67,10 @@ public RNFetchBlobBody(String taskId, RNFetchBlobReq.RequestType type, String ra
5567
mime = contentType;
5668
}
5769

70+
@Override
71+
public long contentLength() {
72+
return contentLength;
73+
}
5874
@Override
5975
public MediaType contentType() {
6076
return mime;
@@ -67,10 +83,11 @@ public void writeTo(BufferedSink sink) throws IOException {
6783
BufferedSink buffer = Okio.buffer(source);
6884
switch (requestType) {
6985
case Form:
70-
writeFormData(sink);
86+
pipeStreamToSink(new FileInputStream(bodyCache), sink);
7187
break;
7288
case SingleFile:
73-
writeOctetData(sink);
89+
if(requestStream != null)
90+
pipeStreamToSink(requestStream, sink);
7491
break;
7592
case AsIs:
7693
writeRawData(sink);
@@ -79,10 +96,58 @@ public void writeTo(BufferedSink sink) throws IOException {
7996
buffer.flush();
8097
}
8198

82-
private void writeFormData(BufferedSink sink) throws IOException {
99+
private void caculateOctetContentLength() {
100+
long total = 0;
101+
// upload from storage
102+
if (rawBody.startsWith(RNFetchBlobConst.FILE_PREFIX)) {
103+
String orgPath = rawBody.substring(RNFetchBlobConst.FILE_PREFIX.length());
104+
orgPath = RNFetchBlobFS.normalizePath(orgPath);
105+
// upload file from assets
106+
if (RNFetchBlobFS.isAsset(orgPath)) {
107+
try {
108+
String assetName = orgPath.replace(RNFetchBlobConst.FILE_PREFIX_BUNDLE_ASSET, "");
109+
contentLength = RNFetchBlob.RCTContext.getAssets().openFd(assetName).getLength();
110+
requestStream = RNFetchBlob.RCTContext.getAssets().open(assetName);
111+
} catch (IOException e) {
112+
// e.printStackTrace();
113+
}
114+
} else {
115+
File f = new File(RNFetchBlobFS.normalizePath(orgPath));
116+
try {
117+
if(!f.exists())
118+
f.createNewFile();
119+
contentLength = f.length();
120+
requestStream = new FileInputStream(f);
121+
} catch (Exception e) {
122+
// callback.invoke(e.getLocalizedMessage(), null);
123+
}
124+
}
125+
} else {
126+
try {
127+
byte[] bytes = Base64.decode(rawBody, 0);
128+
contentLength = bytes.length;
129+
requestStream = new ByteArrayInputStream(bytes);
130+
} catch(Exception ex) {
131+
Log.e("error", ex.getLocalizedMessage());
132+
}
133+
}
134+
}
135+
136+
/**
137+
* Create a temp file that contains content of multipart form data content
138+
* @return The cache file object
139+
* @throws IOException
140+
*/
141+
private File createMultipartBodyCache() throws IOException {
83142
String boundary = "RNFetchBlob-" + mTaskId;
143+
144+
File outputDir = RNFetchBlob.RCTContext.getCacheDir(); // context being the Activity pointer
145+
File outputFile = File.createTempFile("rnfb-form-tmp", "", outputDir);
146+
FileOutputStream os = new FileOutputStream(outputFile);
147+
84148
ArrayList<FormField> fields = countFormDataLength();
85149
ReactApplicationContext ctx = RNFetchBlob.RCTContext;
150+
86151
for(int i = 0;i < fields.size(); i++) {
87152
FormField field = fields.get(i);
88153
String data = field.data;
@@ -95,7 +160,7 @@ private void writeFormData(BufferedSink sink) throws IOException {
95160
if (field.filename != null) {
96161
header += "Content-Disposition: form-data; name=" + name + "; filename=" + field.filename + "\r\n";
97162
header += "Content-Type: " + field.mime + "\r\n\r\n";
98-
sink.write(header.getBytes());
163+
os.write(header.getBytes());
99164
// file field header end
100165
// upload from storage
101166
if (data.startsWith(RNFetchBlobConst.FILE_PREFIX)) {
@@ -106,7 +171,7 @@ private void writeFormData(BufferedSink sink) throws IOException {
106171
try {
107172
String assetName = orgPath.replace(RNFetchBlobConst.FILE_PREFIX_BUNDLE_ASSET, "");
108173
InputStream in = ctx.getAssets().open(assetName);
109-
pipeStreamToSink(in, sink);
174+
pipeStreamToFileStream(in, os);
110175
} catch (IOException e) {
111176
Log.e("RNFetchBlob", "Failed to create form data asset :" + orgPath + ", " + e.getLocalizedMessage() );
112177
}
@@ -116,7 +181,7 @@ private void writeFormData(BufferedSink sink) throws IOException {
116181
File file = new File(RNFetchBlobFS.normalizePath(orgPath));
117182
if(file.exists()) {
118183
FileInputStream fs = new FileInputStream(file);
119-
pipeStreamToSink(fs, sink);
184+
pipeStreamToFileStream(fs, os);
120185
}
121186
else {
122187
Log.e("RNFetchBlob", "Failed to create form data from path :" + orgPath + "file not exists.");
@@ -126,7 +191,7 @@ private void writeFormData(BufferedSink sink) throws IOException {
126191
// base64 embedded file content
127192
else {
128193
byte[] b = Base64.decode(data, 0);
129-
sink.write(b);
194+
os.write(b);
130195
bytesWritten += b.length;
131196
emitUploadProgress();
132197
}
@@ -136,70 +201,30 @@ private void writeFormData(BufferedSink sink) throws IOException {
136201
else {
137202
header += "Content-Disposition: form-data; name=" + name + "\r\n";
138203
header += "Content-Type: " + field.mime + "\r\n\r\n";
139-
sink.write(header.getBytes());
204+
os.write(header.getBytes());
140205
byte[] fieldData = field.data.getBytes();
141206
bytesWritten += fieldData.length;
142-
sink.write(fieldData);
207+
os.write(fieldData);
143208
}
144209
// form end
145-
sink.write("\r\n".getBytes());
210+
os.write("\r\n".getBytes());
146211
}
147212
// close the form
148213
byte[] end = ("--" + boundary + "--\r\n").getBytes();
149-
sink.write(end);
150-
}
151-
152-
/**
153-
* Write octet stream data to request body
154-
* @param sink
155-
*/
156-
private void writeOctetData(BufferedSink sink) throws IOException {
157-
// upload from storage
158-
if (rawBody.startsWith(RNFetchBlobConst.FILE_PREFIX)) {
159-
String orgPath = rawBody.substring(RNFetchBlobConst.FILE_PREFIX.length());
160-
orgPath = RNFetchBlobFS.normalizePath(orgPath);
161-
// upload file from assets
162-
if (RNFetchBlobFS.isAsset(orgPath)) {
163-
try {
164-
String assetName = orgPath.replace(RNFetchBlobConst.FILE_PREFIX_BUNDLE_ASSET, "");
165-
contentLength = RNFetchBlob.RCTContext.getAssets().openFd(assetName).getLength();
166-
requestStream = RNFetchBlob.RCTContext.getAssets().open(assetName);
167-
} catch (IOException e) {
168-
// e.printStackTrace();
169-
}
170-
} else {
171-
File f = new File(RNFetchBlobFS.normalizePath(orgPath));
172-
try {
173-
if(!f.exists())
174-
f.createNewFile();
175-
contentLength = f.length();
176-
requestStream = new FileInputStream(f);
177-
} catch (Exception e) {
178-
// callback.invoke(e.getLocalizedMessage(), null);
179-
}
180-
}
181-
} else {
182-
try {
183-
byte[] bytes = Base64.decode(rawBody, 0);
184-
contentLength = bytes.length;
185-
requestStream = new ByteArrayInputStream(bytes);
186-
} catch(Exception ex) {
187-
188-
Log.e("error", ex.getLocalizedMessage());
189-
}
190-
}
191-
if(requestStream != null)
192-
pipeStreamToSink(requestStream, sink);
193-
214+
os.write(end);
215+
os.flush();
216+
os.close();
217+
return outputFile;
194218
}
195219

196-
197220
/**
198221
* Write data to request body as-is
199222
* @param sink
200223
*/
201224
private void writeRawData(BufferedSink sink) throws IOException {
202-
sink.write(rawBody.getBytes());
225+
byte[] bytes = rawBody.getBytes();
226+
contentLength = bytes.length;
227+
sink.write(bytes);
203228
}
204229

205230
/**
@@ -210,27 +235,29 @@ private void writeRawData(BufferedSink sink) throws IOException {
210235
*/
211236
private void pipeStreamToSink(InputStream stream, BufferedSink sink) throws IOException {
212237
byte [] chunk = new byte[10240];
213-
int read = stream.read(chunk, 0, 10240);
214-
if(read > 0) {
215-
sink.write(chunk, 0, read);
216-
}
217-
bytesWritten += read;
218-
while(read > 0) {
219-
read = stream.read(chunk, 0, 10240);
238+
int read;
239+
while((read = stream.read(chunk, 0, 10240)) > 0) {
220240
if(read > 0) {
221241
sink.write(chunk, 0, read);
222-
bytesWritten += read;
223-
emitUploadProgress();
224242
}
225-
226243
}
227244
stream.close();
228245
}
229246

230-
private void writeBufferToSink(byte [] bytes, BufferedSink sink) throws IOException {
231-
bytesWritten += bytes.length;
232-
sink.write(bytes);
233-
emitUploadProgress();
247+
/**
248+
* Pipe input stream to a file
249+
* @param is The input stream
250+
* @param os The output stream to a file
251+
* @throws IOException
252+
*/
253+
private void pipeStreamToFileStream(InputStream is, FileOutputStream os) throws IOException {
254+
255+
byte[] buf = new byte[10240];
256+
int len;
257+
while ((len = is.read(buf)) > 0) {
258+
os.write(buf, 0, len);
259+
}
260+
is.close();
234261
}
235262

236263
/**
@@ -274,7 +301,7 @@ private ArrayList<FormField> countFormDataLength() {
274301
}
275302
// data field
276303
else {
277-
total += field.data != null ? field.data.length() : 0;
304+
total += field.data != null ? field.data.getBytes().length : 0;
278305
}
279306
}
280307
contentLength = total;

‎src/android/src/main/java/com/RNFetchBlob/RNFetchBlobConst.java

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ public class RNFetchBlobConst {
99
public static final String EVENT_UPLOAD_PROGRESS = "RNFetchBlobProgress-upload";
1010
public static final String EVENT_PROGRESS = "RNFetchBlobProgress";
1111
public static final String EVENT_HTTP_STATE = "RNFetchBlobState";
12+
public static final String EVENT_MESSAGE = "RNFetchBlobMessage";
1213
public static final String FILE_PREFIX = "RNFetchBlob-file://";
1314
public static final String FILE_PREFIX_BUNDLE_ASSET = "bundle-assets://";
1415
public static final String FILE_PREFIX_CONTENT = "content://";

‎src/android/src/main/java/com/RNFetchBlob/RNFetchBlobReq.java

+6-3
Original file line numberDiff line numberDiff line change
@@ -251,11 +251,12 @@ else if(this.options.fileCache == true)
251251
));
252252
break;
253253
case Form:
254+
String boundary = "RNFetchBlob-" + taskId;
254255
builder.method(method, new RNFetchBlobBody(
255256
taskId,
256257
requestType,
257258
rawRequestBodyArray,
258-
MediaType.parse("multipart/form-data; boundary=RNFetchBlob-" + taskId)
259+
MediaType.parse("multipart/form-data; boundary="+ boundary)
259260
));
260261
break;
261262

@@ -301,7 +302,7 @@ public Response intercept(Chain chain) throws IOException {
301302
}
302303
return originalResponse.newBuilder().body(extended).build();
303304
} catch(Exception ex) {
304-
timeout = true;
305+
RNFetchBlobUtils.emitWarningEvent(ex.getLocalizedMessage());
305306
}
306307
return chain.proceed(chain.request());
307308
}
@@ -439,7 +440,9 @@ private void done(Response resp) {
439440
// It uses customized response body which is able to report download progress
440441
// and write response data to destination path.
441442
resp.body().bytes();
442-
} catch (Exception ignored) {}
443+
} catch (Exception ignored) {
444+
ignored.printStackTrace();
445+
}
443446
callback.invoke(null, RNFetchBlobConst.RNFB_RESPONSE_PATH, this.destPath);
444447
break;
445448
default:

‎src/android/src/main/java/com/RNFetchBlob/RNFetchBlobUtils.java

+14
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
package com.RNFetchBlob;
22

3+
import com.facebook.react.bridge.Arguments;
4+
import com.facebook.react.bridge.WritableMap;
5+
import com.facebook.react.modules.core.DeviceEventManagerModule;
6+
37
import java.security.MessageDigest;
48
import java.security.cert.CertificateException;
59

@@ -40,6 +44,16 @@ public static String getMD5(String input) {
4044

4145
}
4246

47+
public static void emitWarningEvent(String data) {
48+
WritableMap args = Arguments.createMap();
49+
args.putString("event", "warn");
50+
args.putString("detail", data);
51+
52+
// emit event to js context
53+
RNFetchBlob.RCTContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
54+
.emit(RNFetchBlobConst.EVENT_MESSAGE, args);
55+
}
56+
4357
public static OkHttpClient.Builder getUnsafeOkHttpClient() {
4458
try {
4559
// Create a trust manager that does not validate certificate chains

0 commit comments

Comments
 (0)