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

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: Use ByteBuffer instead of ByteArrayOutputStream in CronetBufferedOutputStream Created 5 years, 9 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.UploadDataProvider;
8 import org.chromium.net.UploadDataSink;
9
10 import java.io.IOException;
11 import java.io.OutputStream;
12 import java.net.ProtocolException;
13 import java.nio.ByteBuffer;
14
15 /**
16 * An implementation of {@link java.io.OutputStream} that buffers entire request
17 * body in memory. This is used when neither
18 * {@link CronetHttpURLConnection#setFixedLengthStreamingMode}
19 * nor {@link CronetHttpURLConnection#setChunkedStreamingMode} is set.
20 */
21 final class CronetBufferedOutputStream extends OutputStream
22 implements UploadDataProvider {
23 // If content length is not passed in the constructor, this is -1.
24 private final int mInitialContentLength;
25 private final CronetHttpURLConnection mConnection;
26 // Internal buffer that is used to buffer the request body.
27 private ByteBuffer mBuffer;
28 private boolean mConnected = false;
29 private boolean mFirstReadInitiated = 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();
41 }
42
43 if (contentLength > Integer.MAX_VALUE) {
44 throw new IllegalStateException("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(2048);
68 }
69
70 @Override
71 public void write(int oneByte) throws IOException {
72 checkNotExceedContentLength(1);
73 if (mInitialContentLength == -1 && mBuffer.position() == mBuffer.limit() ) {
74 growInternalBuffer(1);
75 }
mmenke 2015/03/31 18:19:32 optional: Suggest moving this surrounding logic i
xunjieli 2015/04/01 17:04:08 Done. You are totally right! that does make the co
76 mBuffer.put((byte) oneByte);
77 }
78
79 @Override
80 public void write(byte[] buffer, int offset, int count) throws IOException {
81 checkNotExceedContentLength(count);
82 if (mInitialContentLength == -1 && mBuffer.limit() - mBuffer.position() < count) {
83 growInternalBuffer(count);
84 }
85 mBuffer.put(buffer, offset, count);
86 }
87
88 /**
89 * Sets {@link #mConnected} to {@code true}.
90 */
91 void setConnected() {
92 mConnected = true;
93 }
94
95 // TODO(xunjieli): implement close().
96
97 /**
98 * Doubles the internal buffer or grows it at least by {@code count} bytes
99 * This method throws an IllegalStateException if the buffer
100 * is not meant to grow because content length is specified.
101 */
102 private void growInternalBuffer(int count) {
103 if (mInitialContentLength != -1) {
104 throw new IllegalStateException("Buffer should not grow.");
105 }
106 int afterSize = Math.max(mBuffer.capacity() * 2, mBuffer.capacity() + co unt);
107 ByteBuffer newByteBuffer = ByteBuffer.allocate(afterSize);
108 mBuffer.flip();
109 newByteBuffer.put(mBuffer);
110 mBuffer = newByteBuffer;
111 }
112
113 /**
114 * Throws {@link java.net.ProtocolException} if adding {@code numBytes} will
115 * exceed content length.
116 */
117 private void checkNotExceedContentLength(int numBytes) throws ProtocolExcept ion {
mmenke 2015/03/31 18:19:32 nit: checkContentLengthNotExceeded? Or could jus
xunjieli 2015/04/01 17:04:08 Done.thanks!
118 if (mConnected) {
119 throw new IllegalStateException("Cannot write after being connected. ");
120 }
121 if (mInitialContentLength != -1
122 && mBuffer.position() + numBytes > mInitialContentLength) {
123 // Error message is to match that of the default implementation.
124 throw new ProtocolException("exceeded content-length limit of "
125 + mInitialContentLength + " bytes");
126 }
127 }
128
129 // Below are UploadDataProvider implementations. Only intended to be used
130 // within Cronet.
131
132 @Override
133 public long getLength() {
134 // This method is supposed to be called just before starting the request .
135 // If content length is not initially passed in, the number of bytes
136 // written will be used as the content length.
137 if (mInitialContentLength == -1) {
138 return mBuffer.position();
139 }
140 return mInitialContentLength;
141 }
142
143 @Override
144 public void read(UploadDataSink uploadDataSink, ByteBuffer byteBuffer) {
145 if (!mFirstReadInitiated) {
146 // This is the first read, so flip the buffer.
147 mBuffer.flip();
148 mFirstReadInitiated = true;
149 }
mmenke 2015/03/31 18:19:32 Can we move this to setConnected, and get rid of m
xunjieli 2015/04/01 17:04:08 Done. Good idea!
150 int oldPos = byteBuffer.position();
151 int availableSpace = byteBuffer.capacity() - byteBuffer.position();
152 if (availableSpace < mBuffer.limit() - mBuffer.position()) {
153 byteBuffer.put(mBuffer.array(), mBuffer.position(), availableSpace);
154 mBuffer.position(mBuffer.position() + availableSpace);
155 } else {
156 byteBuffer.put(mBuffer);
157 }
158 uploadDataSink.onReadSucceeded(false);
159 }
160
161 @Override
162 public void rewind(UploadDataSink uploadDataSink) {
163 mBuffer.position(0);
164 uploadDataSink.onRewindSucceeded();
165 }
166 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698