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

Side by Side Diff: components/cronet/android/java/src/org/chromium/net/urlconnection/CronetBufferedOutputStream.java

Issue 966743003: [Cronet] Implement getOutputStream in CronetHttpURLConnection (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@chunked_support
Patch Set: Remove unused Created 5 years, 8 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
(Empty)
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
3 // found in the LICENSE file.
4
5 package org.chromium.net.urlconnection;
6
7 import org.chromium.net.UploadDataSink;
8
9 import java.io.IOException;
10 import java.net.ProtocolException;
11 import java.nio.ByteBuffer;
12
13 /**
14 * An implementation of {@link java.io.OutputStream} that buffers entire request
15 * body in memory. This is used when neither
16 * {@link CronetHttpURLConnection#setFixedLengthStreamingMode}
17 * nor {@link CronetHttpURLConnection#setChunkedStreamingMode} is set.
18 */
19 final class CronetBufferedOutputStream extends CronetOutputStream {
20 // QUIC uses a read buffer of 14520 bytes, SPDY uses 2852 bytes, and normal
21 // stream uses 16384 bytes. Therefore, use 16384 for now to avoid growing
22 // the buffer too many times.
23 private static final int INITIAL_BUFFER_SIZE = 16384;
24 // If content length is not passed in the constructor, this is -1.
25 private final int mInitialContentLength;
26 private final CronetHttpURLConnection mConnection;
27 // Internal buffer that is used to buffer the request body.
28 private ByteBuffer mBuffer;
29 private boolean mConnected = false;
30
31 /**
32 * Package protected constructor.
33 * @param connection The CronetHttpURLConnection object.
34 * @param contentLength The content length of the request body. It must not
35 * be smaller than 0 or bigger than {@link Integer.MAX_VALUE}.
36 */
37 CronetBufferedOutputStream(final CronetHttpURLConnection connection,
38 final long contentLength) {
39 if (connection == null) {
40 throw new NullPointerException("Argument connection cannot be null." );
41 }
42
43 if (contentLength > Integer.MAX_VALUE) {
44 throw new IllegalArgumentException("Use setFixedLengthStreamingMode( )"
45 + " or setChunkedStreamingMode() for requests larger than 2GB.") ;
46 }
47 if (contentLength < 0) {
48 throw new IllegalArgumentException("Content length < 0.");
49 }
50 mConnection = connection;
51 mInitialContentLength = (int) contentLength;
52 mBuffer = ByteBuffer.allocate(mInitialContentLength);
53 }
54
55 /**
56 * Package protected constructor used when content length is not known.
57 * @param connection The CronetHttpURLConnection object.
58 */
59 CronetBufferedOutputStream(final CronetHttpURLConnection connection) {
60 if (connection == null) {
61 throw new NullPointerException();
62 }
63
64 mConnection = connection;
65 mInitialContentLength = -1;
66 // Buffering without knowing content-length.
67 mBuffer = ByteBuffer.allocate(INITIAL_BUFFER_SIZE);
68 }
69
70 @Override
71 public void write(int oneByte) throws IOException {
72 ensureCanWrite(1);
73 mBuffer.put((byte) oneByte);
74 }
75
76 @Override
77 public void write(byte[] buffer, int offset, int count) throws IOException {
78 ensureCanWrite(count);
79 mBuffer.put(buffer, offset, count);
80 }
81
82 // TODO(xunjieli): implement close().
83
84 /**
85 * Ensures that {@code count} bytes can be written to the internal buffer.
86 */
87 private void ensureCanWrite(int count) throws IOException {
88 if (mInitialContentLength != -1
89 && mBuffer.position() + count > mInitialContentLength) {
90 // Error message is to match that of the default implementation.
91 throw new ProtocolException("exceeded content-length limit of "
92 + mInitialContentLength + " bytes");
93 }
94 if (mConnected) {
95 throw new IllegalStateException("Cannot write after being connected. ");
96 }
97 if (mInitialContentLength != -1) {
98 // If mInitialContentLength is known, the buffer should not grow.
99 return;
100 }
101 if (mBuffer.limit() - mBuffer.position() > count) {
102 // If there is enough capacity, the buffer should not grow.
103 return;
104 }
105 int afterSize = Math.max(mBuffer.capacity() * 2, mBuffer.capacity() + co unt);
106 ByteBuffer newByteBuffer = ByteBuffer.allocate(afterSize);
107 mBuffer.flip();
108 newByteBuffer.put(mBuffer);
109 mBuffer = newByteBuffer;
110 }
111
112 // Below are CronetOutputStream implementations:
113
114 /**
115 * Sets {@link #mConnected} to {@code true}.
116 */
117 @Override
118 void setConnected() throws IOException {
119 mConnected = true;
120 if (mBuffer.position() < mInitialContentLength) {
121 throw new ProtocolException("Content received is less than Content-L ength");
122 }
123 // Flip the buffer to prepare it for UploadDataProvider read calls.
124 mBuffer.flip();
125 }
126
127 @Override
128 void checkReceivedEnoughContent() throws IOException {
129 // Already checked in setConnected. Skip the check here, since mBuffer
130 // might be flipped.
131 }
132
133 @Override
134 public long getLength() {
135 // This method is supposed to be called just before starting the request .
136 // If content length is not initially passed in, the number of bytes
137 // written will be used as the content length.
138 // TODO(xunjieli): Think of a less fragile way, since getLength() can be
139 // potentially called in other places in the future.
140 if (mInitialContentLength == -1) {
141 return mBuffer.position();
142 }
143 return mInitialContentLength;
144 }
145
146 @Override
147 public void read(UploadDataSink uploadDataSink, ByteBuffer byteBuffer) {
148 int availableSpace = byteBuffer.capacity() - byteBuffer.position();
149 if (availableSpace < mBuffer.limit() - mBuffer.position()) {
150 byteBuffer.put(mBuffer.array(), mBuffer.position(), availableSpace);
151 mBuffer.position(mBuffer.position() + availableSpace);
152 } else {
153 byteBuffer.put(mBuffer);
154 }
155 uploadDataSink.onReadSucceeded(false);
156 }
157
158 @Override
159 public void rewind(UploadDataSink uploadDataSink) {
160 mBuffer.position(0);
161 uploadDataSink.onRewindSucceeded();
162 }
163 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698