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

Side by Side 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 Paul's 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 unified diff | Download patch
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 package org.chromium.net.urlconnection; 5 package org.chromium.net.urlconnection;
6 6
7 import org.chromium.base.VisibleForTesting; 7 import org.chromium.base.VisibleForTesting;
8 import org.chromium.net.UploadDataProvider; 8 import org.chromium.net.UploadDataProvider;
9 import org.chromium.net.UploadDataSink; 9 import org.chromium.net.UploadDataSink;
10 10
(...skipping 12 matching lines...) Expand all
23 final class CronetFixedModeOutputStream extends CronetOutputStream { 23 final class CronetFixedModeOutputStream extends CronetOutputStream {
24 // CronetFixedModeOutputStream buffers up to this value and wait for UploadD ataStream 24 // CronetFixedModeOutputStream buffers up to this value and wait for UploadD ataStream
25 // to consume the data. This field is non-final, so it can be changed for te sts. 25 // to consume the data. This field is non-final, so it can be changed for te sts.
26 // Using 16384 bytes is because the internal read buffer is 14520 for QUIC, 26 // Using 16384 bytes is because the internal read buffer is 14520 for QUIC,
27 // 16384 for SPDY, and 16384 for normal HTTP/1.1 stream. 27 // 16384 for SPDY, and 16384 for normal HTTP/1.1 stream.
28 @VisibleForTesting 28 @VisibleForTesting
29 private static int sDefaultBufferLength = 16384; 29 private static int sDefaultBufferLength = 16384;
30 private final CronetHttpURLConnection mConnection; 30 private final CronetHttpURLConnection mConnection;
31 private final MessageLoop mMessageLoop; 31 private final MessageLoop mMessageLoop;
32 private final long mContentLength; 32 private final long mContentLength;
33 // Internal buffer for storing the bytes written by consumer and for providi ng
pauljensen 2016/06/10 17:45:44 "written" has several possible meanings here (e.g.
xunjieli 2016/06/10 18:48:12 Done.
34 // bytes for the native stack to consume in UploadDataProvider.read().
pauljensen 2016/06/10 17:45:44 the consuming isn't really done in UploadDataProvi
xunjieli 2016/06/10 18:48:12 Done.
35 // CronetFixedModeOutputStream allows consumer to write up to sDefaultBuffer Length,
pauljensen 2016/06/10 17:45:44 consumer->the client
pauljensen 2016/06/10 17:45:45 sDefaultBufferLength->sDefaultBufferLength bytes
pauljensen 2016/06/10 17:45:45 write->provide
xunjieli 2016/06/10 18:48:12 Done.
xunjieli 2016/06/10 18:48:12 Done.
xunjieli 2016/06/10 18:48:13 Done.
36 // and wait for UploadDataProvider.read() to be called so mBuffer is cleared
pauljensen 2016/06/10 17:45:44 so->, after which point
xunjieli 2016/06/10 18:48:11 Done.
37 // for next round of writing. During writing, the buffer's position points
pauljensen 2016/06/10 17:45:44 for next round of writing->so the client can fill
pauljensen 2016/06/10 17:45:44 During writing->While the client is filling the bu
xunjieli 2016/06/10 18:48:11 Done.
xunjieli 2016/06/10 18:48:12 Done.
38 // to the next byte to be written, and limit is the index at which no byte
pauljensen 2016/06/10 17:45:44 "is the index..."->"points to the end of the buffe
pauljensen 2016/06/10 17:45:44 written->provided by the client
xunjieli 2016/06/10 18:48:12 Done.
39 // should be written. The buffer is flipped before it is passed to the
40 // UploadDataProvider for consuming. Once it is flipped, buffer position
41 // points to the next byte to be read, and limit is the index at which no
pauljensen 2016/06/10 17:45:44 read->copied to the UploadDataSink
pauljensen 2016/06/10 17:45:44 "is the index..."->"points to the end of the data
xunjieli 2016/06/10 18:48:11 Done.
xunjieli 2016/06/10 18:48:12 Done.
42 // byte should be read. When the UploadDataProvider is done reading from
pauljensen 2016/06/10 17:45:44 "is done..."->"has provided all remaining bytes fr
xunjieli 2016/06/10 18:48:11 Done.
43 // mBuffer, it clears mBuffer for next round of writing.
33 private final ByteBuffer mBuffer; 44 private final ByteBuffer mBuffer;
34 private final UploadDataProvider mUploadDataProvider = new UploadDataProvide rImpl(); 45 private final UploadDataProvider mUploadDataProvider = new UploadDataProvide rImpl();
35 private long mBytesWritten; 46 private long mBytesWritten;
36 47
37 /** 48 /**
38 * Package protected constructor. 49 * Package protected constructor.
39 * @param connection The CronetHttpURLConnection object. 50 * @param connection The CronetHttpURLConnection object.
40 * @param contentLength The content length of the request body. Non-zero for 51 * @param contentLength The content length of the request body. Non-zero for
41 * non-chunked upload. 52 * non-chunked upload.
42 */ 53 */
(...skipping 10 matching lines...) Expand all
53 int bufferSize = (int) Math.min(mContentLength, sDefaultBufferLength); 64 int bufferSize = (int) Math.min(mContentLength, sDefaultBufferLength);
54 mBuffer = ByteBuffer.allocate(bufferSize); 65 mBuffer = ByteBuffer.allocate(bufferSize);
55 mConnection = connection; 66 mConnection = connection;
56 mMessageLoop = messageLoop; 67 mMessageLoop = messageLoop;
57 mBytesWritten = 0; 68 mBytesWritten = 0;
58 } 69 }
59 70
60 @Override 71 @Override
61 public void write(int oneByte) throws IOException { 72 public void write(int oneByte) throws IOException {
62 checkNotExceedContentLength(1); 73 checkNotExceedContentLength(1);
63 while (mBuffer.position() == mBuffer.limit()) { 74 ensureBufferHasRemaining();
64 // Wait until buffer is consumed.
65 mMessageLoop.loop();
66 }
67 mBuffer.put((byte) oneByte); 75 mBuffer.put((byte) oneByte);
68 mBytesWritten++; 76 mBytesWritten++;
69 if (mBytesWritten == mContentLength) { 77 uploadIfComplete();
70 // Entire post data has been received. Now wait for network stack to
71 // read it.
72 mMessageLoop.loop();
73 }
74 } 78 }
75 79
76 @Override 80 @Override
77 public void write(byte[] buffer, int offset, int count) throws IOException { 81 public void write(byte[] buffer, int offset, int count) throws IOException {
78 if (buffer.length - offset < count || offset < 0 || count < 0) { 82 if (buffer.length - offset < count || offset < 0 || count < 0) {
79 throw new IndexOutOfBoundsException(); 83 throw new IndexOutOfBoundsException();
80 } 84 }
81 checkNotExceedContentLength(count); 85 checkNotExceedContentLength(count);
82 if (count == 0) {
83 return;
84 }
85 int toSend = count; 86 int toSend = count;
86 while (toSend > 0) { 87 while (toSend > 0) {
87 if (mBuffer.position() == mBuffer.limit()) { 88 ensureBufferHasRemaining();
88 // Wait until buffer is consumed. 89 int sent = Math.min(toSend, mBuffer.remaining());
89 mMessageLoop.loop();
90 }
91 int sent = Math.min(toSend, mBuffer.limit() - mBuffer.position());
92 mBuffer.put(buffer, offset + count - toSend, sent); 90 mBuffer.put(buffer, offset + count - toSend, sent);
93 toSend -= sent; 91 toSend -= sent;
94 } 92 }
95 mBytesWritten += count; 93 mBytesWritten += count;
94 uploadIfComplete();
95 }
96
97 /**
98 * If {@code mBuffer} is full, wait until it is consumed and there is
99 * space to write more data to it.
100 */
101 private void ensureBufferHasRemaining() {
102 if (!mBuffer.hasRemaining()) {
103 uploadBufferInternal();
104 }
105 }
106
107 /**
108 * Waits the native stack to upload data since all bytes have been written.
pauljensen 2016/06/10 17:45:44 data->mBuffer's contents
pauljensen 2016/06/10 17:45:44 since...->because the client has provided all byte
pauljensen 2016/06/10 17:45:44 the->for the
xunjieli 2016/06/10 18:48:12 Done.
xunjieli 2016/06/10 18:48:12 Done.
xunjieli 2016/06/10 18:48:12 Done.
109 */
110 private void uploadIfComplete() {
96 if (mBytesWritten == mContentLength) { 111 if (mBytesWritten == mContentLength) {
97 // Entire post data has been received. Now wait for network stack to 112 // Entire post data has been received. Now wait for network stack to
98 // read it. 113 // read it.
99 mMessageLoop.loop(); 114 uploadBufferInternal();
100 } 115 }
101 } 116 }
102 117
103 /** 118 /**
119 * Helper function to upload the buffer to the native stack. This function
pauljensen 2016/06/10 17:45:44 buffer->{@code mBuffer}
xunjieli 2016/06/10 18:48:12 Done.
120 * blocks until {@code mBuffer} is consumed and there is space to write more
121 * data.
122 */
123 private void uploadBufferInternal() {
124 mBuffer.flip();
125 mMessageLoop.loop();
126 }
127
128 /**
104 * Throws {@link java.net.ProtocolException} if adding {@code numBytes} will 129 * Throws {@link java.net.ProtocolException} if adding {@code numBytes} will
105 * exceed content length. 130 * exceed content length.
106 */ 131 */
107 private void checkNotExceedContentLength(int numBytes) throws ProtocolExcept ion { 132 private void checkNotExceedContentLength(int numBytes) throws ProtocolExcept ion {
108 if (mBytesWritten + numBytes > mContentLength) { 133 if (mBytesWritten + numBytes > mContentLength) {
109 throw new ProtocolException("expected " 134 throw new ProtocolException("expected "
110 + (mContentLength - mBytesWritten) + " bytes but received " 135 + (mContentLength - mBytesWritten) + " bytes but received "
111 + numBytes); 136 + numBytes);
112 } 137 }
113 } 138 }
(...skipping 20 matching lines...) Expand all
134 } 159 }
135 160
136 private class UploadDataProviderImpl extends UploadDataProvider { 161 private class UploadDataProviderImpl extends UploadDataProvider {
137 @Override 162 @Override
138 public long getLength() { 163 public long getLength() {
139 return mContentLength; 164 return mContentLength;
140 } 165 }
141 166
142 @Override 167 @Override
143 public void read(final UploadDataSink uploadDataSink, final ByteBuffer b yteBuffer) { 168 public void read(final UploadDataSink uploadDataSink, final ByteBuffer b yteBuffer) {
144 final int availableSpace = byteBuffer.remaining(); 169 if (byteBuffer.remaining() >= mBuffer.remaining()) {
145 if (availableSpace < mBuffer.position()) {
146 // byteBuffer does not have enough capacity, so only put a porti on
147 // of mBuffer in it.
148 byteBuffer.put(mBuffer.array(), 0, availableSpace);
149 mBuffer.position(availableSpace);
150 // Move remaining buffer to the head of the buffer for use in th e
151 // next read call.
152 mBuffer.compact();
153 } else {
154 // byteBuffer has enough capacity to hold the content of mBuffer .
155 mBuffer.flip();
156 byteBuffer.put(mBuffer); 170 byteBuffer.put(mBuffer);
157 // Reuse this buffer. 171 // Reuse this buffer.
158 mBuffer.clear(); 172 mBuffer.clear();
173 uploadDataSink.onReadSucceeded(false);
159 // Quit message loop so embedder can write more data. 174 // Quit message loop so embedder can write more data.
160 mMessageLoop.quit(); 175 mMessageLoop.quit();
176 } else {
177 mBuffer.position(mBuffer.position() + byteBuffer.remaining());
178 byteBuffer.put(mBuffer.array(), mBuffer.position() - byteBuffer. remaining(),
179 byteBuffer.remaining());
180 uploadDataSink.onReadSucceeded(false);
161 } 181 }
162 uploadDataSink.onReadSucceeded(false);
163 } 182 }
164 183
165 @Override 184 @Override
166 public void rewind(UploadDataSink uploadDataSink) { 185 public void rewind(UploadDataSink uploadDataSink) {
167 uploadDataSink.onRewindError( 186 uploadDataSink.onRewindError(
168 new HttpRetryException("Cannot retry streamed Http body", -1 )); 187 new HttpRetryException("Cannot retry streamed Http body", -1 ));
169 } 188 }
170 } 189 }
171 190
172 /** 191 /**
173 * Sets the default buffer length for use in tests. 192 * Sets the default buffer length for use in tests.
174 */ 193 */
175 @VisibleForTesting 194 @VisibleForTesting
176 static void setDefaultBufferLengthForTesting(int length) { 195 static void setDefaultBufferLengthForTesting(int length) {
177 sDefaultBufferLength = length; 196 sDefaultBufferLength = length;
178 } 197 }
179 } 198 }
OLDNEW
« no previous file with comments | « components/cronet/android/BUILD.gn ('k') | components/cronet/android/test/javatests/src/org/chromium/net/QuicUploadTest.java » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698