Skip to content

Commit e0d91bf

Browse files
committed
[Android] Replaced ForwardingSink with OutputStream to fix progress
Using a ForwardingSink, an IllegalStateException was thrown in Okio's RealBufferedSink when attempting to write to a sink that was closed. Additionally, it did not send updates for non-input stream request bodies. Replacing with an OutputStream-based sink prevents the crash by throwing an IOException instead, and fixes the progress updates. Also, now get the content length before writing to avoid incorrect total size for input streams. Addresses issues: 10423/11016.
1 parent 5c1e626 commit e0d91bf

File tree

1 file changed

+42
-27
lines changed

1 file changed

+42
-27
lines changed

ReactAndroid/src/main/java/com/facebook/react/modules/network/ProgressRequestBody.java

Lines changed: 42 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -9,60 +9,75 @@
99

1010
package com.facebook.react.modules.network;
1111

12+
import com.facebook.common.internal.CountingOutputStream;
13+
1214
import java.io.IOException;
15+
1316
import okhttp3.MediaType;
1417
import okhttp3.RequestBody;
1518
import okio.BufferedSink;
16-
import okio.Buffer;
17-
import okio.Sink;
18-
import okio.ForwardingSink;
1919
import okio.Okio;
20+
import okio.Sink;
2021

2122
public class ProgressRequestBody extends RequestBody {
2223

2324
private final RequestBody mRequestBody;
2425
private final ProgressListener mProgressListener;
2526
private BufferedSink mBufferedSink;
27+
private long mContentLength = 0L;
2628

2729
public ProgressRequestBody(RequestBody requestBody, ProgressListener progressListener) {
28-
mRequestBody = requestBody;
29-
mProgressListener = progressListener;
30+
mRequestBody = requestBody;
31+
mProgressListener = progressListener;
3032
}
3133

3234
@Override
3335
public MediaType contentType() {
34-
return mRequestBody.contentType();
36+
return mRequestBody.contentType();
3537
}
3638

3739
@Override
3840
public long contentLength() throws IOException {
39-
return mRequestBody.contentLength();
41+
if (mContentLength == 0) {
42+
mContentLength = mRequestBody.contentLength();
43+
}
44+
return mContentLength;
4045
}
4146

4247
@Override
4348
public void writeTo(BufferedSink sink) throws IOException {
44-
if (mBufferedSink == null) {
45-
mBufferedSink = Okio.buffer(sink(sink));
46-
}
47-
mRequestBody.writeTo(mBufferedSink);
48-
mBufferedSink.flush();
49+
if (mBufferedSink == null) {
50+
mBufferedSink = Okio.buffer(outputStreamSink(sink));
51+
}
52+
53+
// contentLength changes for input streams, since we're using inputStream.available(),
54+
// so get the length before writing to the sink
55+
contentLength();
56+
57+
mRequestBody.writeTo(mBufferedSink);
58+
mBufferedSink.flush();
4959
}
5060

51-
private Sink sink(Sink sink) {
52-
return new ForwardingSink(sink) {
53-
long bytesWritten = 0L;
54-
long contentLength = 0L;
61+
private Sink outputStreamSink(BufferedSink sink) {
62+
return Okio.sink(new CountingOutputStream(sink.outputStream()) {
63+
@Override
64+
public void write(byte[] data, int offset, int byteCount) throws IOException {
65+
super.write(data, offset, byteCount);
66+
sendProgressUpdate();
67+
}
5568

56-
@Override
57-
public void write(Buffer source, long byteCount) throws IOException {
58-
super.write(source, byteCount);
59-
if (contentLength == 0) {
60-
contentLength = contentLength();
61-
}
62-
bytesWritten += byteCount;
63-
mProgressListener.onProgress(
64-
bytesWritten, contentLength, bytesWritten == contentLength);
65-
}
66-
};
69+
@Override
70+
public void write(int data) throws IOException {
71+
super.write(data);
72+
sendProgressUpdate();
73+
}
74+
75+
private void sendProgressUpdate() throws IOException {
76+
long bytesWritten = getCount();
77+
long contentLength = contentLength();
78+
mProgressListener.onProgress(
79+
bytesWritten, contentLength, bytesWritten == contentLength);
80+
}
81+
});
6782
}
6883
}

0 commit comments

Comments
 (0)