Index: components/cronet/android/java/src/org/chromium/net/urlconnection/CronetBufferedOutputStream.java |
diff --git a/components/cronet/android/java/src/org/chromium/net/urlconnection/CronetBufferedOutputStream.java b/components/cronet/android/java/src/org/chromium/net/urlconnection/CronetBufferedOutputStream.java |
new file mode 100644 |
index 0000000000000000000000000000000000000000..9eb03bcf82c386f4b2e26e3129d8ada5a28f1ee3 |
--- /dev/null |
+++ b/components/cronet/android/java/src/org/chromium/net/urlconnection/CronetBufferedOutputStream.java |
@@ -0,0 +1,105 @@ |
+// Copyright 2015 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+package org.chromium.net.urlconnection; |
+ |
+import org.chromium.net.UploadDataProvider; |
+import org.chromium.net.UploadDataSink; |
+ |
+import java.io.ByteArrayOutputStream; |
+import java.io.IOException; |
+import java.io.OutputStream; |
+import java.nio.ByteBuffer; |
+ |
+/** |
+ * An implementation of {@link java.io.OutputStream} that buffers entire request |
+ * body in memory. This is used when neither |
+ * {@link CronetHttpURLConnection#setFixedLengthStreamingMode} |
+ * or {@link CronetHttpURLConnection#setChunkedStreamingMode} is set. |
+ */ |
+final class CronetBufferedOutputStream extends OutputStream |
+ implements UploadDataProvider { |
+ private final int mInitialContentLength; |
+ private final CronetHttpURLConnection mConnection; |
+ // Internal buffer that is used to buffer the request body. |
+ private final ByteArrayOutputStream mBuffer; |
+ // Number of bytes consumed by the native UploadDataStream. |
+ private int mBytesConsumed; |
+ |
+ /** |
+ * Packaged protected constructor. |
mef
2015/03/10 16:48:22
nit: Package protected constructor.
xunjieli
2015/03/12 21:55:09
Done.
|
+ * @param connection The CronetHttpURLConnection object. |
+ * @param contentLength The content length of the request body. If content |
+ * length cannot be determined in advance, use -1. |
+ */ |
+ CronetBufferedOutputStream(final CronetHttpURLConnection connection, |
+ final long contentLength) { |
+ if (connection == null) { |
+ throw new NullPointerException(); |
+ } |
+ |
+ if (contentLength > Integer.MAX_VALUE) { |
mef
2015/03/10 16:48:22
what if it is negative, but not -1?
xunjieli
2015/03/12 21:55:09
Done. Right, we should handle that case. To make a
|
+ throw new IllegalStateException("Use setFixedLengthStreamingMode()" |
+ + " or setChunkedStreamingMode() for requests larger than 2GB."); |
+ } |
+ mConnection = connection; |
+ mInitialContentLength = (int) contentLength; |
+ if (mInitialContentLength == -1) { |
+ // Bufferring without knowing content-length. |
+ mBuffer = new ByteArrayOutputStream(); |
+ } else { |
+ mBuffer = new ByteArrayOutputStream(mInitialContentLength); |
+ } |
+ mBytesConsumed = 0; |
+ } |
+ |
+ @Override |
+ public void write(int oneByte) throws IOException { |
+ mBuffer.write((byte) oneByte); |
+ if (mBuffer.size() == mInitialContentLength) { |
mef
2015/03/10 16:48:22
what happens if app will write more than expected?
xunjieli
2015/03/12 21:55:09
Done. Good catch, it should fail with a java.net.P
|
+ // Entire post data has been received. Now start the request. |
+ mConnection.connect(); |
+ } |
+ } |
+ |
+ @Override |
+ public void write(byte[] buffer, int offset, int count) throws IOException { |
+ mBuffer.write(buffer, offset, count); |
+ if (mInitialContentLength != -1 && mBuffer.size() > mInitialContentLength) { |
+ throw new IllegalStateException("Writing out of bound."); |
+ } |
+ if (mBuffer.size() == mInitialContentLength) { |
mef
2015/03/10 16:48:22
When does it connect() if mInitialContentLength ==
xunjieli
2015/03/12 21:55:09
The embedder calls connect() or any function that
|
+ // Entire post data has been received. Now start the request. |
+ mConnection.connect(); |
+ } |
+ } |
+ |
+ @Override |
mef
2015/03/10 16:48:22
nit: Add comment that these methods are implementa
xunjieli
2015/03/12 21:55:09
Done.
|
+ public long getLength() { |
+ // This method is supposed to be called just before starting the request. |
+ // If content length is not initially passed in, the number of bytes |
+ // written will be used as the content length. |
+ if (mInitialContentLength < 0) { |
+ return mBuffer.size(); |
+ } |
+ return mInitialContentLength; |
+ } |
+ |
+ @Override |
+ public void read(UploadDataSink uploadDataSink, ByteBuffer byteBuffer) { |
+ int toConsume = Math.min(byteBuffer.remaining(), |
+ mBuffer.size() - mBytesConsumed); |
+ if (toConsume > 0) { |
+ byteBuffer.put(mBuffer.toByteArray(), mBytesConsumed, toConsume); |
+ } |
+ mBytesConsumed += toConsume; |
+ uploadDataSink.onReadSucceeded(false); |
+ } |
+ |
+ @Override |
+ public void rewind(UploadDataSink uploadDataSink) { |
+ mBytesConsumed = 0; |
+ uploadDataSink.onRewindSucceeded(); |
+ } |
+} |