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

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

Issue 849903002: [Cronet] Upload support for async APIs (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Combined with Matt's CL Created 5 years, 10 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 2014 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;
6
7 import org.chromium.base.CalledByNative;
8 import org.chromium.base.JNINamespace;
9
10 import java.nio.ByteBuffer;
11 import java.util.concurrent.Executor;
12
13 /**
14 * Pass an upload body to a UrlRequest using an UploadDataProvider.
15 */
16 @JNINamespace("cronet")
17 public class CronetUploadDataStream implements UploadDataSink {
18 // These are never changed, once a request starts.
19 private final Executor mExecutor;
20 private final UploadDataProvider mDataProvider;
21 private final long mLength;
22 private CronetUrlRequest mRequest;
23
24 // Reusable read task, to reduce redundant memory allocation.
25 private final Runnable mReadTask = new Runnable() {
26 @Override
27 public void run() {
28 synchronized (mLock) {
29 if (mReading || mRewinding || mByteBuffer == null
30 || mUploadDataStreamDelegate == 0) {
31 throw new IllegalStateException(
32 "Unexpected readData call.");
33 }
34 mReading = true;
35 }
36
37 try {
38 mDataProvider.read(CronetUploadDataStream.this, mByteBuffer);
39 } catch (Exception exception) {
40 onError(exception);
41 }
42 }
43 };
44
45 private ByteBuffer mByteBuffer = null;
46
47 // Lock that protects all subsequent variables. The delegate has to be
48 // protected to ensure safe shutdown, mReading and mRewinding are protected
49 // to robustly detect getting read/rewind results more often than expected.
50 private final Object mLock = new Object();
51
52 // Native adapter object, owned by the CronetUploadDataStream. It's only
53 // deleted after the native UploadDataStream object is destroyed. All
54 // access to the adapter is synchronized, for safe usage and cleanup.
55 private long mUploadDataStreamDelegate;
56
57 private boolean mReading = false;
58 private boolean mRewinding = false;
59
60 public CronetUploadDataStream(UploadDataProvider dataProvider,
61 Executor executor) {
62 mExecutor = executor;
63 mDataProvider = dataProvider;
64 mLength = mDataProvider.getLength();
65 }
66
67 @SuppressWarnings("unused")
68 @CalledByNative
69 void readData(ByteBuffer byteBuffer) {
70 mByteBuffer = byteBuffer;
71 try {
72 mExecutor.execute(mReadTask);
73 // nativeOnReadSucceeded(mUploadDataStreamDelegate, 0, 0, true);
74 } catch (Exception exception) {
75 onError(exception);
76 }
77 }
78
79 // TODO(mmenke): Consider implementing a cancel method.
80 // currently wait for any pending read to complete.
81
82 @SuppressWarnings("unused")
83 @CalledByNative
84 void rewind() {
85 Runnable task = new Runnable() {
86 // @Override
87 public void run() {
88 synchronized (mLock) {
89 if (mReading || mRewinding
90 || mUploadDataStreamDelegate == 0) {
91 throw new IllegalStateException(
92 "Unexpected rewind call.");
93 }
94 mRewinding = true;
95 try {
96 mDataProvider.rewind(CronetUploadDataStream.this);
97 } catch (Exception exception) {
98 onError(exception);
99 }
100 }
101 }
102 };
103
104 mExecutor.execute(task);
105 }
106
107 @SuppressWarnings("unused")
108 @CalledByNative
109 void onAdapterDestroyed() {
110 Runnable task = new Runnable() {
111 // @Override
112 public void run() {
113 destroyAdapter();
114 }
115 };
116
117 mExecutor.execute(task);
118 }
119
120 private void onError(Exception exception) {
121 synchronized (mLock) {
122 mReading = false;
123 mRewinding = false;
124 mByteBuffer = null;
125 }
126
127 // Just fail the request - simpler to fail directly, and
128 // UploadDataStream only supports failing during initialization, not
129 // while reading.
130 mRequest.onUploadException(exception);
131 }
132
133 @Override
134 public void onReadSucceeded(boolean lastChunk) {
135 synchronized (mLock) {
136 if (!mReading) {
137 throw new IllegalStateException("Non-existent read succeeded.");
138 }
139 if (lastChunk && mLength >= 0) {
140 throw new IllegalArgumentException(
141 "Non-chunked upload can't have last chunk");
142 }
143 int position = mByteBuffer.position();
144 int limit = mByteBuffer.limit();
145
146 mByteBuffer = null;
147 mReading = false;
148
149 // Request may been canceled already.
150 if (mUploadDataStreamDelegate == 0) {
151 return;
152 }
153 nativeOnReadSucceeded(mUploadDataStreamDelegate, position, limit,
154 lastChunk);
155 }
156 }
157
158 public void onReadError(Exception exception) {
159 synchronized (mLock) {
160 if (!mReading) {
161 throw new IllegalStateException("Non-existent read failed.");
162 }
163 // Request may been canceled already.
164 if (mUploadDataStreamDelegate == 0) {
165 return;
166 }
167 onError(exception);
168 }
169 }
170
171 public void onRewindSucceeded() {
172 synchronized (mLock) {
173 if (!mRewinding) {
174 throw new IllegalStateException(
175 "Non-existent rewind succeeded.");
176 }
177 mRewinding = false;
178 // Request may been canceled already.
179 if (mUploadDataStreamDelegate == 0) {
180 return;
181 }
182 nativeOnRewindSucceeded(mUploadDataStreamDelegate);
183 }
184 }
185
186 public void onRewindError(Exception exception) {
187 synchronized (mLock) {
188 if (!mRewinding) {
189 throw new IllegalStateException("Non-existent rewind failed.");
190 }
191 // Request may been canceled already.
192 if (mUploadDataStreamDelegate == 0) {
193 return;
194 }
195 onError(exception);
196 }
197 }
198
199 /**
200 * The adapter is owned by the CronetUploadDataStream, so it can be
201 * destroyed safely; however, destruction is initiated by the destruction of
202 * the C++ URLUploadStream.
203 */
204 void destroyAdapter() {
205 synchronized (mLock) {
206 if (mUploadDataStreamDelegate == 0)
207 return;
208 nativeDestroyDelegate(mUploadDataStreamDelegate);
209 mUploadDataStreamDelegate = 0;
210 }
211 }
212
213 /**
214 * Creates native objects and attaches them to the underlying request
215 * adapter object.
216 * TODO(mmenke): If more types of native upload streams are needed, create
217 * an interface with just this method, to minimize CronetURLRequest's
218 * dependencies on each upload stream type.
219 */
220 void attachToRequest(CronetUrlRequest request, long requestAdapter) {
221 if (mLength < 0) {
222 // TODO(mmenke): Add tests and remove this line.
223 throw new IllegalArgumentException(
224 "Chunked uploads not supported.");
225 }
226 mRequest = request;
227 mUploadDataStreamDelegate =
228 nativeAttachUploadDataToRequest(requestAdapter, mLength);
229 }
230
231 /**
232 * Creates a native UploadDataStreamDelegate and UploadDataStreamAdapter
233 * for testing.
234 */
235 public long createAdapter() {
236 mUploadDataStreamDelegate = nativeCreateDelegate();
237 return nativeCreateAdapter(mLength, mUploadDataStreamDelegate);
238 }
239
240 // Native methods are implemented in upload_data_stream_adapter.cc.
241
242 private native long nativeAttachUploadDataToRequest(long urlRequestAdapter,
243 long length);
244
245 private native long nativeCreateDelegate();
246
247 private native long nativeCreateAdapter(long length, long delegate);
248
249 private native void nativeOnReadSucceeded(long uploadDataStreamDelegate,
250 int position, int limit, boolean finalChunk);
251
252 private native void nativeOnRewindSucceeded(long uploadDataStreamDelegate);
253
254 private static native void nativeDestroyDelegate(
255 long uploadDataStreamDelegate);
256 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698