Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1257)

Unified Diff: components/cronet/android/java/src/org/chromium/net/urlconnection/CronetFixedModeOutputStream.java

Issue 2055083002: [Cronet] Fix CronetFixedModeOutputStream to not write more bytes than specified (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: address comments Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: components/cronet/android/java/src/org/chromium/net/urlconnection/CronetFixedModeOutputStream.java
diff --git a/components/cronet/android/java/src/org/chromium/net/urlconnection/CronetFixedModeOutputStream.java b/components/cronet/android/java/src/org/chromium/net/urlconnection/CronetFixedModeOutputStream.java
index f6e005335ae4104e6bf1b8444324ce89999908fb..6f83f0022c053c5193e85b3fdcaf92264a55da81 100644
--- a/components/cronet/android/java/src/org/chromium/net/urlconnection/CronetFixedModeOutputStream.java
+++ b/components/cronet/android/java/src/org/chromium/net/urlconnection/CronetFixedModeOutputStream.java
@@ -30,6 +30,20 @@ final class CronetFixedModeOutputStream extends CronetOutputStream {
private final CronetHttpURLConnection mConnection;
private final MessageLoop mMessageLoop;
private final long mContentLength;
+ // Internal buffer for holding bytes from the client until the bytes are
+ // copied to the UploadDataSink in UploadDataProvider.read().
+ // CronetFixedModeOutputStream allows client to provide up to
+ // sDefaultBufferLength bytes, and wait for UploadDataProvider.read() to be
+ // called after which point mBuffer is cleared so client can fill in again.
+ // While the client is filling the buffer (via {@code write()}), the buffer's
+ // position points to the next byte to be provided by the client, and limit
+ // points to the end of the buffer. The buffer is flipped before it is
+ // passed to the UploadDataProvider for consuming. Once it is flipped,
+ // buffer position points to the next byte to be copied to the
+ // UploadDataSink, and limit points to the end of data available to be
+ // copied to UploadDataSink. When the UploadDataProvider has provided all
+ // remaining bytes from the buffer to UploadDataSink, it clears the buffer
+ // so client can fill it again.
private final ByteBuffer mBuffer;
private final UploadDataProvider mUploadDataProvider = new UploadDataProviderImpl();
private long mBytesWritten;
@@ -60,17 +74,10 @@ final class CronetFixedModeOutputStream extends CronetOutputStream {
@Override
public void write(int oneByte) throws IOException {
checkNotExceedContentLength(1);
- while (mBuffer.position() == mBuffer.limit()) {
- // Wait until buffer is consumed.
- mMessageLoop.loop();
- }
+ ensureBufferHasRemaining();
mBuffer.put((byte) oneByte);
mBytesWritten++;
- if (mBytesWritten == mContentLength) {
- // Entire post data has been received. Now wait for network stack to
- // read it.
- mMessageLoop.loop();
- }
+ uploadIfComplete();
}
@Override
@@ -79,28 +86,51 @@ final class CronetFixedModeOutputStream extends CronetOutputStream {
throw new IndexOutOfBoundsException();
}
checkNotExceedContentLength(count);
- if (count == 0) {
- return;
- }
int toSend = count;
while (toSend > 0) {
- if (mBuffer.position() == mBuffer.limit()) {
- // Wait until buffer is consumed.
- mMessageLoop.loop();
- }
- int sent = Math.min(toSend, mBuffer.limit() - mBuffer.position());
+ ensureBufferHasRemaining();
+ int sent = Math.min(toSend, mBuffer.remaining());
mBuffer.put(buffer, offset + count - toSend, sent);
toSend -= sent;
}
mBytesWritten += count;
+ uploadIfComplete();
+ }
+
+ /**
+ * If {@code mBuffer} is full, wait until it is consumed and there is
+ * space to write more data to it.
+ */
+ private void ensureBufferHasRemaining() throws IOException {
+ if (!mBuffer.hasRemaining()) {
+ uploadBufferInternal();
+ }
+ }
+
+ /**
+ * Waits for the native stack to upload {@code mBuffer}'s contents because
+ * the client has provided all bytes to be uploaded and there is no need to
+ * wait for or expect the client to provide more bytes.
+ */
+ private void uploadIfComplete() throws IOException {
if (mBytesWritten == mContentLength) {
// Entire post data has been received. Now wait for network stack to
// read it.
- mMessageLoop.loop();
+ uploadBufferInternal();
}
}
/**
+ * Helper function to upload {@code mBuffer} to the native stack. This
+ * function blocks until {@code mBuffer} is consumed and there is space to
+ * write more data.
+ */
+ private void uploadBufferInternal() throws IOException {
+ mBuffer.flip();
+ mMessageLoop.loop();
+ }
+
+ /**
* Throws {@link java.net.ProtocolException} if adding {@code numBytes} will
* exceed content length.
*/
@@ -141,25 +171,20 @@ final class CronetFixedModeOutputStream extends CronetOutputStream {
@Override
public void read(final UploadDataSink uploadDataSink, final ByteBuffer byteBuffer) {
- final int availableSpace = byteBuffer.remaining();
- if (availableSpace < mBuffer.position()) {
- // byteBuffer does not have enough capacity, so only put a portion
- // of mBuffer in it.
- byteBuffer.put(mBuffer.array(), 0, availableSpace);
- mBuffer.position(availableSpace);
- // Move remaining buffer to the head of the buffer for use in the
- // next read call.
- mBuffer.compact();
- } else {
- // byteBuffer has enough capacity to hold the content of mBuffer.
- mBuffer.flip();
+ if (byteBuffer.remaining() >= mBuffer.remaining()) {
byteBuffer.put(mBuffer);
// Reuse this buffer.
mBuffer.clear();
+ uploadDataSink.onReadSucceeded(false);
// Quit message loop so embedder can write more data.
mMessageLoop.quit();
+ } else {
+ int oldLimit = mBuffer.limit();
+ mBuffer.limit(mBuffer.position() + byteBuffer.remaining());
+ byteBuffer.put(mBuffer);
+ mBuffer.limit(oldLimit);
+ uploadDataSink.onReadSucceeded(false);
}
- uploadDataSink.onReadSucceeded(false);
}
@Override

Powered by Google App Engine
This is Rietveld 408576698