13
13
import java .io .ByteArrayInputStream ;
14
14
import java .io .File ;
15
15
import java .io .FileInputStream ;
16
+ import java .io .FileNotFoundException ;
17
+ import java .io .FileOutputStream ;
16
18
import java .io .IOException ;
17
19
import java .io .InputStream ;
20
+ import java .nio .ByteBuffer ;
21
+ import java .nio .MappedByteBuffer ;
18
22
import java .util .ArrayList ;
19
23
import java .util .HashMap ;
20
24
33
37
public class RNFetchBlobBody extends RequestBody {
34
38
35
39
InputStream requestStream ;
36
- long contentLength ;
40
+ long contentLength = 0 ;
37
41
long bytesWritten = 0 ;
38
42
ReadableArray form ;
39
43
String mTaskId ;
40
44
String rawBody ;
41
45
RNFetchBlobReq .RequestType requestType ;
42
46
MediaType mime ;
47
+ File bodyCache ;
48
+
43
49
44
50
public RNFetchBlobBody (String taskId , RNFetchBlobReq .RequestType type , ReadableArray form , MediaType contentType ) {
45
51
this .mTaskId = taskId ;
46
52
this .form = form ;
47
53
requestType = type ;
48
54
mime = contentType ;
55
+ try {
56
+ bodyCache = createMultipartBodyCache ();
57
+ contentLength = bodyCache .length ();
58
+ } catch (IOException e ) {
59
+ e .printStackTrace ();
60
+ }
49
61
}
50
62
51
63
public RNFetchBlobBody (String taskId , RNFetchBlobReq .RequestType type , String rawBody , MediaType contentType ) {
@@ -55,6 +67,10 @@ public RNFetchBlobBody(String taskId, RNFetchBlobReq.RequestType type, String ra
55
67
mime = contentType ;
56
68
}
57
69
70
+ @ Override
71
+ public long contentLength () {
72
+ return contentLength ;
73
+ }
58
74
@ Override
59
75
public MediaType contentType () {
60
76
return mime ;
@@ -67,10 +83,11 @@ public void writeTo(BufferedSink sink) throws IOException {
67
83
BufferedSink buffer = Okio .buffer (source );
68
84
switch (requestType ) {
69
85
case Form :
70
- writeFormData ( sink );
86
+ pipeStreamToSink ( new FileInputStream ( bodyCache ), sink );
71
87
break ;
72
88
case SingleFile :
73
- writeOctetData (sink );
89
+ if (requestStream != null )
90
+ pipeStreamToSink (requestStream , sink );
74
91
break ;
75
92
case AsIs :
76
93
writeRawData (sink );
@@ -79,10 +96,58 @@ public void writeTo(BufferedSink sink) throws IOException {
79
96
buffer .flush ();
80
97
}
81
98
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 {
83
142
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
+
84
148
ArrayList <FormField > fields = countFormDataLength ();
85
149
ReactApplicationContext ctx = RNFetchBlob .RCTContext ;
150
+
86
151
for (int i = 0 ;i < fields .size (); i ++) {
87
152
FormField field = fields .get (i );
88
153
String data = field .data ;
@@ -95,7 +160,7 @@ private void writeFormData(BufferedSink sink) throws IOException {
95
160
if (field .filename != null ) {
96
161
header += "Content-Disposition: form-data; name=" + name + "; filename=" + field .filename + "\r \n " ;
97
162
header += "Content-Type: " + field .mime + "\r \n \r \n " ;
98
- sink .write (header .getBytes ());
163
+ os .write (header .getBytes ());
99
164
// file field header end
100
165
// upload from storage
101
166
if (data .startsWith (RNFetchBlobConst .FILE_PREFIX )) {
@@ -106,7 +171,7 @@ private void writeFormData(BufferedSink sink) throws IOException {
106
171
try {
107
172
String assetName = orgPath .replace (RNFetchBlobConst .FILE_PREFIX_BUNDLE_ASSET , "" );
108
173
InputStream in = ctx .getAssets ().open (assetName );
109
- pipeStreamToSink (in , sink );
174
+ pipeStreamToFileStream (in , os );
110
175
} catch (IOException e ) {
111
176
Log .e ("RNFetchBlob" , "Failed to create form data asset :" + orgPath + ", " + e .getLocalizedMessage () );
112
177
}
@@ -116,7 +181,7 @@ private void writeFormData(BufferedSink sink) throws IOException {
116
181
File file = new File (RNFetchBlobFS .normalizePath (orgPath ));
117
182
if (file .exists ()) {
118
183
FileInputStream fs = new FileInputStream (file );
119
- pipeStreamToSink (fs , sink );
184
+ pipeStreamToFileStream (fs , os );
120
185
}
121
186
else {
122
187
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 {
126
191
// base64 embedded file content
127
192
else {
128
193
byte [] b = Base64 .decode (data , 0 );
129
- sink .write (b );
194
+ os .write (b );
130
195
bytesWritten += b .length ;
131
196
emitUploadProgress ();
132
197
}
@@ -136,70 +201,30 @@ private void writeFormData(BufferedSink sink) throws IOException {
136
201
else {
137
202
header += "Content-Disposition: form-data; name=" + name + "\r \n " ;
138
203
header += "Content-Type: " + field .mime + "\r \n \r \n " ;
139
- sink .write (header .getBytes ());
204
+ os .write (header .getBytes ());
140
205
byte [] fieldData = field .data .getBytes ();
141
206
bytesWritten += fieldData .length ;
142
- sink .write (fieldData );
207
+ os .write (fieldData );
143
208
}
144
209
// form end
145
- sink .write ("\r \n " .getBytes ());
210
+ os .write ("\r \n " .getBytes ());
146
211
}
147
212
// close the form
148
213
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 ;
194
218
}
195
219
196
-
197
220
/**
198
221
* Write data to request body as-is
199
222
* @param sink
200
223
*/
201
224
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 );
203
228
}
204
229
205
230
/**
@@ -210,27 +235,29 @@ private void writeRawData(BufferedSink sink) throws IOException {
210
235
*/
211
236
private void pipeStreamToSink (InputStream stream , BufferedSink sink ) throws IOException {
212
237
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 ) {
220
240
if (read > 0 ) {
221
241
sink .write (chunk , 0 , read );
222
- bytesWritten += read ;
223
- emitUploadProgress ();
224
242
}
225
-
226
243
}
227
244
stream .close ();
228
245
}
229
246
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 ();
234
261
}
235
262
236
263
/**
@@ -274,7 +301,7 @@ private ArrayList<FormField> countFormDataLength() {
274
301
}
275
302
// data field
276
303
else {
277
- total += field .data != null ? field .data .length () : 0 ;
304
+ total += field .data != null ? field .data .getBytes (). length : 0 ;
278
305
}
279
306
}
280
307
contentLength = total ;
0 commit comments