OLD | NEW |
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.net.UploadDataProvider; | 7 import org.chromium.net.UploadDataProvider; |
8 import org.chromium.net.UploadDataSink; | 8 import org.chromium.net.UploadDataSink; |
9 | 9 |
10 import java.io.IOException; | 10 import java.io.IOException; |
11 import java.net.HttpRetryException; | 11 import java.net.HttpRetryException; |
12 import java.nio.ByteBuffer; | 12 import java.nio.ByteBuffer; |
13 | 13 |
14 /** | 14 /** |
15 * An implementation of {@link java.io.OutputStream} to send data to a server, | 15 * An implementation of {@link java.io.OutputStream} to send data to a server, |
16 * when {@link CronetHttpURLConnection#setChunkedStreamingMode} is used. | 16 * when {@link CronetHttpURLConnection#setChunkedStreamingMode} is used. |
17 * This implementation does not buffer the entire request body in memory. | 17 * This implementation does not buffer the entire request body in memory. |
18 * It does not support rewind. Note that {@link #write} should only be called | 18 * It does not support rewind. Note that {@link #write} should only be called |
19 * from the thread on which the {@link #mConnection} is created. | 19 * from the thread on which the {@link #mConnection} is created. |
20 */ | 20 */ |
21 final class CronetChunkedOutputStream extends CronetOutputStream { | 21 final class CronetChunkedOutputStream extends CronetOutputStream { |
22 private final CronetHttpURLConnection mConnection; | 22 private final CronetHttpURLConnection mConnection; |
23 private final MessageLoop mMessageLoop; | 23 private final MessageLoop mMessageLoop; |
24 private final ByteBuffer mBuffer; | 24 private final ByteBuffer mBuffer; |
25 private final UploadDataProvider mUploadDataProvider = new UploadDataProvide
rImpl(); | 25 private final UploadDataProvider mUploadDataProvider = new UploadDataProvide
rImpl(); |
26 private long mBytesWritten; | 26 private long mBytesWritten; |
27 private boolean mLastChunk = false; | 27 private boolean mLastChunk = false; |
28 private boolean mClosed = false; | |
29 | 28 |
30 /** | 29 /** |
31 * Package protected constructor. | 30 * Package protected constructor. |
32 * @param connection The CronetHttpURLConnection object. | 31 * @param connection The CronetHttpURLConnection object. |
33 * @param contentLength The content length of the request body. Non-zero for | 32 * @param contentLength The content length of the request body. Non-zero for |
34 * non-chunked upload. | 33 * non-chunked upload. |
35 */ | 34 */ |
36 CronetChunkedOutputStream( | 35 CronetChunkedOutputStream( |
37 CronetHttpURLConnection connection, int chunkLength, MessageLoop mes
sageLoop) { | 36 CronetHttpURLConnection connection, int chunkLength, MessageLoop mes
sageLoop) { |
38 if (connection == null) { | 37 if (connection == null) { |
(...skipping 22 matching lines...) Expand all Loading... |
61 @Override | 60 @Override |
62 public void write(byte[] buffer, int offset, int count) throws IOException { | 61 public void write(byte[] buffer, int offset, int count) throws IOException { |
63 checkNotClosed(); | 62 checkNotClosed(); |
64 if (buffer.length - offset < count || offset < 0 || count < 0) { | 63 if (buffer.length - offset < count || offset < 0 || count < 0) { |
65 throw new IndexOutOfBoundsException(); | 64 throw new IndexOutOfBoundsException(); |
66 } | 65 } |
67 if (count == 0) { | 66 if (count == 0) { |
68 return; | 67 return; |
69 } | 68 } |
70 int toSend = count; | 69 int toSend = count; |
| 70 // TODO(xunjieli): refactor commond code with CronetFixedModeOutputStrea
m. |
71 while (toSend > 0) { | 71 while (toSend > 0) { |
72 if (mBuffer.position() == mBuffer.limit()) { | 72 if (mBuffer.position() == mBuffer.limit()) { |
| 73 checkNotClosed(); |
73 // Wait until buffer is consumed. | 74 // Wait until buffer is consumed. |
74 mMessageLoop.loop(); | 75 mMessageLoop.loop(); |
75 } | 76 } |
76 int sent = Math.min(toSend, mBuffer.limit() - mBuffer.position()); | 77 int sent = Math.min(toSend, mBuffer.limit() - mBuffer.position()); |
77 mBuffer.put(buffer, offset + count - toSend, sent); | 78 mBuffer.put(buffer, offset + count - toSend, sent); |
78 toSend -= sent; | 79 toSend -= sent; |
79 } | 80 } |
80 mBytesWritten += count; | 81 mBytesWritten += count; |
81 } | 82 } |
82 | 83 |
83 @Override | 84 @Override |
84 public void close() throws IOException { | 85 public void close() throws IOException { |
| 86 super.close(); |
85 // Last chunk is written. | 87 // Last chunk is written. |
86 mLastChunk = true; | 88 mLastChunk = true; |
87 mClosed = true; | |
88 } | |
89 | |
90 private void checkNotClosed() throws IOException { | |
91 if (mClosed) { | |
92 throw new IOException("Stream has been closed."); | |
93 } | |
94 } | 89 } |
95 | 90 |
96 // Below are CronetOutputStream implementations: | 91 // Below are CronetOutputStream implementations: |
97 | 92 |
98 @Override | 93 @Override |
99 void setConnected() throws IOException { | 94 void setConnected() throws IOException { |
100 // Do nothing. | 95 // Do nothing. |
101 } | 96 } |
102 | 97 |
103 @Override | 98 @Override |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
142 } | 137 } |
143 } | 138 } |
144 | 139 |
145 @Override | 140 @Override |
146 public void rewind(UploadDataSink uploadDataSink) { | 141 public void rewind(UploadDataSink uploadDataSink) { |
147 uploadDataSink.onRewindError( | 142 uploadDataSink.onRewindError( |
148 new HttpRetryException("Cannot retry streamed Http body", -1
)); | 143 new HttpRetryException("Cannot retry streamed Http body", -1
)); |
149 } | 144 } |
150 } | 145 } |
151 } | 146 } |
OLD | NEW |