1
1
package com .RNFetchBlob ;
2
2
3
3
import android .util .Base64 ;
4
- import android .util .Log ;
5
4
6
5
import com .facebook .react .bridge .Arguments ;
7
6
import com .facebook .react .bridge .ReactApplicationContext ;
13
12
import java .io .ByteArrayInputStream ;
14
13
import java .io .File ;
15
14
import java .io .FileInputStream ;
16
- import java .io .FileNotFoundException ;
17
15
import java .io .FileOutputStream ;
18
16
import java .io .IOException ;
19
17
import java .io .InputStream ;
20
- import java .nio .ByteBuffer ;
21
- import java .nio .MappedByteBuffer ;
22
18
import java .util .ArrayList ;
23
- import java .util .HashMap ;
24
19
25
20
import okhttp3 .MediaType ;
26
21
import okhttp3 .RequestBody ;
27
- import okhttp3 .FormBody ;
28
- import okio .Buffer ;
29
22
import okio .BufferedSink ;
30
- import okio .ForwardingSink ;
31
- import okio .Okio ;
32
- import okio .Sink ;
33
23
34
24
/**
35
25
* Created by wkh237 on 2016/7/11.
@@ -38,7 +28,6 @@ public class RNFetchBlobBody extends RequestBody{
38
28
39
29
InputStream requestStream ;
40
30
long contentLength = 0 ;
41
- long bytesWritten = 0 ;
42
31
ReadableArray form ;
43
32
String mTaskId ;
44
33
String rawBody ;
@@ -47,59 +36,84 @@ public class RNFetchBlobBody extends RequestBody{
47
36
File bodyCache ;
48
37
49
38
39
+ /**
40
+ * Single file or raw content request constructor
41
+ * @param taskId
42
+ * @param type
43
+ * @param form
44
+ * @param contentType
45
+ */
50
46
public RNFetchBlobBody (String taskId , RNFetchBlobReq .RequestType type , ReadableArray form , MediaType contentType ) {
51
47
this .mTaskId = taskId ;
52
48
this .form = form ;
53
49
requestType = type ;
54
50
mime = contentType ;
55
51
try {
56
52
bodyCache = createMultipartBodyCache ();
53
+ requestStream = new FileInputStream (bodyCache );
57
54
contentLength = bodyCache .length ();
58
- } catch (IOException e ) {
59
- e .printStackTrace ();
55
+ } catch (Exception ex ) {
56
+ ex .printStackTrace ();
57
+ RNFetchBlobUtils .emitWarningEvent ("RNFetchBlob failed to create request multipart body :" + ex .getLocalizedMessage ());
60
58
}
61
59
}
62
60
61
+ /**
62
+ * Multipart request constructor
63
+ * @param taskId
64
+ * @param type
65
+ * @param rawBody
66
+ * @param contentType
67
+ */
63
68
public RNFetchBlobBody (String taskId , RNFetchBlobReq .RequestType type , String rawBody , MediaType contentType ) {
64
69
this .mTaskId = taskId ;
65
70
requestType = type ;
66
71
this .rawBody = rawBody ;
67
72
mime = contentType ;
68
- if (rawBody != null ) {
69
- if (requestType == RNFetchBlobReq .RequestType .AsIs )
70
- contentLength = rawBody .length ();
71
- else
72
- contentLength = caculateOctetContentLength ();
73
+ if (rawBody == null ) {
74
+ this .rawBody = "" ;
75
+ requestType = RNFetchBlobReq .RequestType .AsIs ;
76
+ }
77
+ try {
78
+ switch (requestType ) {
79
+ case SingleFile :
80
+ requestStream = getReuqestStream ();
81
+ contentLength = requestStream .available ();
82
+ break ;
83
+ case AsIs :
84
+ contentLength = this .rawBody .getBytes ().length ;
85
+ break ;
86
+ case Others :
87
+ break ;
88
+ }
89
+ } catch (Exception ex ) {
90
+ ex .printStackTrace ();
91
+ RNFetchBlobUtils .emitWarningEvent ("RNFetchBlob failed to create single content request body :" + ex .getLocalizedMessage () + "\r \n " );
73
92
}
93
+
74
94
}
75
95
76
96
@ Override
77
97
public long contentLength () {
78
98
return contentLength ;
79
99
}
100
+
80
101
@ Override
81
102
public MediaType contentType () {
82
103
return mime ;
83
104
}
84
105
85
106
@ Override
86
- public void writeTo (BufferedSink sink ) throws IOException {
87
-
88
- ProgressReportingSource source = new ProgressReportingSource (sink , mTaskId );
89
- BufferedSink buffer = Okio .buffer (source );
90
- switch (requestType ) {
91
- case Form :
92
- pipeStreamToSink (new FileInputStream (bodyCache ), sink );
93
- break ;
94
- case SingleFile :
95
- if (requestStream != null )
96
- pipeStreamToSink (requestStream , sink );
97
- break ;
98
- case AsIs :
99
- writeRawData (sink );
100
- break ;
107
+ public void writeTo (BufferedSink sink ) {
108
+ try {
109
+ if (requestType == RNFetchBlobReq .RequestType .AsIs )
110
+ sink .write (rawBody .getBytes ());
111
+ else
112
+ pipeStreamToSink (requestStream , sink );
113
+ } catch (Exception ex ) {
114
+ RNFetchBlobUtils .emitWarningEvent (ex .getLocalizedMessage ());
115
+ ex .printStackTrace ();
101
116
}
102
- buffer .flush ();
103
117
}
104
118
105
119
boolean clearRequestBody () {
@@ -114,8 +128,8 @@ boolean clearRequestBody() {
114
128
return true ;
115
129
}
116
130
117
- private long caculateOctetContentLength () {
118
- long total = 0 ;
131
+ private InputStream getReuqestStream () throws Exception {
132
+
119
133
// upload from storage
120
134
if (rawBody .startsWith (RNFetchBlobConst .FILE_PREFIX )) {
121
135
String orgPath = rawBody .substring (RNFetchBlobConst .FILE_PREFIX .length ());
@@ -124,32 +138,30 @@ private long caculateOctetContentLength() {
124
138
if (RNFetchBlobFS .isAsset (orgPath )) {
125
139
try {
126
140
String assetName = orgPath .replace (RNFetchBlobConst .FILE_PREFIX_BUNDLE_ASSET , "" );
127
- total += RNFetchBlob .RCTContext .getAssets ().openFd (assetName ).getLength ();
128
- requestStream = RNFetchBlob .RCTContext .getAssets ().open (assetName );
129
- } catch (IOException e ) {
130
- RNFetchBlobUtils .emitWarningEvent (e .getLocalizedMessage ());
141
+ return RNFetchBlob .RCTContext .getAssets ().open (assetName );
142
+ } catch (Exception e ) {
143
+ throw new Exception ("error when getting request stream from asset : " +e .getLocalizedMessage ());
131
144
}
132
145
} else {
133
146
File f = new File (RNFetchBlobFS .normalizePath (orgPath ));
134
147
try {
135
148
if (!f .exists ())
136
149
f .createNewFile ();
137
- total += f .length ();
138
- requestStream = new FileInputStream (f );
150
+ return new FileInputStream (f );
139
151
} catch (Exception e ) {
140
- RNFetchBlobUtils . emitWarningEvent ( "RNetchBlob error when counting content length : " +e .getLocalizedMessage ());
152
+ throw new Exception ( " error when getting request stream : " +e .getLocalizedMessage ());
141
153
}
142
154
}
143
- } else {
155
+ }
156
+ // base 64 encoded
157
+ else {
144
158
try {
145
159
byte [] bytes = Base64 .decode (rawBody , 0 );
146
- requestStream = new ByteArrayInputStream (bytes );
147
- total += requestStream .available ();
160
+ return new ByteArrayInputStream (bytes );
148
161
} catch (Exception ex ) {
149
- RNFetchBlobUtils . emitWarningEvent ( "RNetchBlob error when counting content length : " +ex .getLocalizedMessage ());
162
+ throw new Exception ( " error when getting request stream : " + ex .getLocalizedMessage ());
150
163
}
151
164
}
152
- return total ;
153
165
}
154
166
155
167
/**
@@ -192,7 +204,7 @@ private File createMultipartBodyCache() throws IOException {
192
204
InputStream in = ctx .getAssets ().open (assetName );
193
205
pipeStreamToFileStream (in , os );
194
206
} catch (IOException e ) {
195
- RNFetchBlobUtils .emitWarningEvent ("RNFetchBlob Failed to create form data asset :" + orgPath + ", " + e .getLocalizedMessage () );
207
+ RNFetchBlobUtils .emitWarningEvent ("Failed to create form data asset :" + orgPath + ", " + e .getLocalizedMessage () );
196
208
}
197
209
}
198
210
// data from normal files
@@ -203,16 +215,14 @@ private File createMultipartBodyCache() throws IOException {
203
215
pipeStreamToFileStream (fs , os );
204
216
}
205
217
else {
206
- RNFetchBlobUtils .emitWarningEvent ("RNFetchBlob Failed to create form data from path :" + orgPath + ", file not exists." );
218
+ RNFetchBlobUtils .emitWarningEvent ("Failed to create form data from path :" + orgPath + ", file not exists." );
207
219
}
208
220
}
209
221
}
210
222
// base64 embedded file content
211
223
else {
212
224
byte [] b = Base64 .decode (data , 0 );
213
225
os .write (b );
214
- bytesWritten += b .length ;
215
- emitUploadProgress ();
216
226
}
217
227
218
228
}
@@ -222,7 +232,6 @@ private File createMultipartBodyCache() throws IOException {
222
232
header += "Content-Type: " + field .mime + "\r \n \r \n " ;
223
233
os .write (header .getBytes ());
224
234
byte [] fieldData = field .data .getBytes ();
225
- bytesWritten += fieldData .length ;
226
235
os .write (fieldData );
227
236
}
228
237
// form end
@@ -236,28 +245,22 @@ private File createMultipartBodyCache() throws IOException {
236
245
return outputFile ;
237
246
}
238
247
239
- /**
240
- * Write data to request body as-is
241
- * @param sink
242
- */
243
- private void writeRawData (BufferedSink sink ) throws IOException {
244
- byte [] bytes = rawBody .getBytes ();
245
- contentLength = bytes .length ;
246
- sink .write (bytes );
247
- }
248
-
249
248
/**
250
249
* Pipe input stream to request body output stream
251
250
* @param stream The input stream
252
251
* @param sink The request body buffer sink
253
252
* @throws IOException
254
253
*/
255
- private void pipeStreamToSink (InputStream stream , BufferedSink sink ) throws IOException {
254
+ private void pipeStreamToSink (InputStream stream , BufferedSink sink ) throws Exception {
255
+
256
256
byte [] chunk = new byte [10240 ];
257
+ int totalWritten = 0 ;
257
258
int read ;
258
259
while ((read = stream .read (chunk , 0 , 10240 )) > 0 ) {
259
260
if (read > 0 ) {
260
261
sink .write (chunk , 0 , read );
262
+ totalWritten += read ;
263
+ emitUploadProgress (totalWritten );
261
264
}
262
265
}
263
266
stream .close ();
@@ -356,45 +359,19 @@ public FormField(ReadableMap rawData) {
356
359
}
357
360
}
358
361
359
- private void emitUploadProgress () {
362
+ /**
363
+ * Emit progress event
364
+ * @param written
365
+ */
366
+ private void emitUploadProgress (int written ) {
360
367
WritableMap args = Arguments .createMap ();
361
368
args .putString ("taskId" , mTaskId );
362
- args .putString ("written" , String .valueOf (bytesWritten ));
369
+ args .putString ("written" , String .valueOf (written ));
363
370
args .putString ("total" , String .valueOf (contentLength ));
364
371
365
372
// emit event to js context
366
373
RNFetchBlob .RCTContext .getJSModule (DeviceEventManagerModule .RCTDeviceEventEmitter .class )
367
374
.emit (RNFetchBlobConst .EVENT_UPLOAD_PROGRESS , args );
368
375
}
369
376
370
- private final class ProgressReportingSource extends ForwardingSink {
371
-
372
- private long bytesWritten = 0 ;
373
- private String mTaskId ;
374
- private Sink delegate ;
375
-
376
- public ProgressReportingSource (Sink delegate , String taskId ) {
377
- super (delegate );
378
- this .mTaskId = taskId ;
379
- this .delegate = delegate ;
380
- }
381
-
382
- @ Override
383
- public void write (Buffer source , long byteCount ) throws IOException {
384
- delegate .write (source , byteCount );
385
- // on progress, emit RNFetchBlobProgress upload progress event with ticketId,
386
- // bytesWritten, and totalSize
387
- bytesWritten += byteCount ;
388
- WritableMap args = Arguments .createMap ();
389
- args .putString ("taskId" , mTaskId );
390
- args .putString ("written" , String .valueOf (bytesWritten ));
391
- args .putString ("total" , String .valueOf (contentLength ));
392
-
393
- if (RNFetchBlobReq .isReportUploadProgress (mTaskId )) {
394
- // emit event to js context
395
- RNFetchBlob .RCTContext .getJSModule (DeviceEventManagerModule .RCTDeviceEventEmitter .class )
396
- .emit (RNFetchBlobConst .EVENT_UPLOAD_PROGRESS , args );
397
- }
398
- }
399
- }
400
377
}
0 commit comments