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

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

Issue 966743003: [Cronet] Implement getOutputStream in CronetHttpURLConnection (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@chunked_support
Patch Set: 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
1 // Copyright 2014 The Chromium Authors. All rights reserved. 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 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 android.util.Log;
7 import android.util.Pair; 8 import android.util.Pair;
8 9
9 import org.chromium.net.ExtendedResponseInfo; 10 import org.chromium.net.ExtendedResponseInfo;
10 import org.chromium.net.ResponseInfo; 11 import org.chromium.net.ResponseInfo;
12 import org.chromium.net.UploadDataProvider;
11 import org.chromium.net.UrlRequest; 13 import org.chromium.net.UrlRequest;
12 import org.chromium.net.UrlRequestContext; 14 import org.chromium.net.UrlRequestContext;
13 import org.chromium.net.UrlRequestException; 15 import org.chromium.net.UrlRequestException;
14 import org.chromium.net.UrlRequestListener; 16 import org.chromium.net.UrlRequestListener;
15 17
16 import java.io.FileNotFoundException; 18 import java.io.FileNotFoundException;
17 import java.io.IOException; 19 import java.io.IOException;
18 import java.io.InputStream; 20 import java.io.InputStream;
21 import java.io.OutputStream;
19 import java.net.HttpURLConnection; 22 import java.net.HttpURLConnection;
20 import java.net.MalformedURLException; 23 import java.net.MalformedURLException;
24 import java.net.ProtocolException;
21 import java.net.URL; 25 import java.net.URL;
22 import java.nio.ByteBuffer; 26 import java.nio.ByteBuffer;
23 import java.util.ArrayList; 27 import java.util.ArrayList;
24 import java.util.Collections; 28 import java.util.Collections;
25 import java.util.List; 29 import java.util.List;
26 import java.util.Map; 30 import java.util.Map;
27 import java.util.TreeMap; 31 import java.util.TreeMap;
28 32
29 /** 33 /**
30 * An implementation of HttpURLConnection that uses Cronet to send requests and 34 * An implementation of HttpURLConnection that uses Cronet to send requests and
31 * receive response. This class inherits a {@code connected} field from the 35 * receive response. This class inherits a {@code connected} field from the
32 * superclass. That field indicates whether a connection has ever been 36 * superclass. That field indicates whether a connection has ever been
33 * attempted. 37 * attempted.
34 */ 38 */
35 public class CronetHttpURLConnection extends HttpURLConnection { 39 public class CronetHttpURLConnection extends HttpURLConnection {
40 private static final String TAG = "CronetHttpURLConnection";
36 private final UrlRequestContext mUrlRequestContext; 41 private final UrlRequestContext mUrlRequestContext;
37 private final MessageLoop mMessageLoop; 42 private final MessageLoop mMessageLoop;
38 private final UrlRequest mRequest; 43 private final UrlRequest mRequest;
39 private final List<Pair<String, String>> mRequestHeaders; 44 private final List<Pair<String, String>> mRequestHeaders;
40 45
41 private CronetInputStream mInputStream; 46 private CronetInputStream mInputStream;
47 private OutputStream mOutputStream;
42 private ResponseInfo mResponseInfo; 48 private ResponseInfo mResponseInfo;
43 private UrlRequestException mException; 49 private UrlRequestException mException;
44 private ByteBuffer mResponseByteBuffer; 50 private ByteBuffer mResponseByteBuffer;
45 private boolean mOnRedirectCalled = false; 51 private boolean mOnRedirectCalled = false;
52 // A long version of the superclass field of the same name.
53 private long mFixedContentLength = -1;
pauljensen 2015/03/04 16:44:11 Can this just be replaced with super.fixedContentL
xunjieli 2015/03/05 17:43:11 Done. Didn't realize this field exists in 1.7. Was
xunjieli 2015/03/05 18:28:22 Looks like this long version is in API level 19 +.
pauljensen 2015/03/06 13:07:43 :( ya...
46 54
47 protected CronetHttpURLConnection(URL url, 55 public CronetHttpURLConnection(URL url,
48 UrlRequestContext urlRequestContext) { 56 UrlRequestContext urlRequestContext) {
49 super(url); 57 super(url);
50 mUrlRequestContext = urlRequestContext; 58 mUrlRequestContext = urlRequestContext;
51 mMessageLoop = new MessageLoop(); 59 mMessageLoop = new MessageLoop();
52 mRequest = mUrlRequestContext.createRequest(url.toString(), 60 mRequest = mUrlRequestContext.createRequest(url.toString(),
53 new CronetUrlRequestListener(), mMessageLoop); 61 new CronetUrlRequestListener(), mMessageLoop);
54 mInputStream = new CronetInputStream(this); 62 mInputStream = new CronetInputStream(this);
55 mRequestHeaders = new ArrayList<Pair<String, String>>(); 63 mRequestHeaders = new ArrayList<Pair<String, String>>();
56 } 64 }
57 65
58 /** 66 /**
59 * Opens a connection to the resource. If the connect method is called when 67 * Opens a connection to the resource. If the connect method is called when
60 * the connection has already been opened (indicated by the connected field 68 * the connection has already been opened (indicated by the connected field
61 * having the value true), the call is ignored unless an exception is thrown 69 * having the value true), the call is ignored unless an exception is thrown
62 * previously, in which case, the exception will be rethrown. 70 * previously, in which case, the exception will be rethrown.
63 */ 71 */
64 @Override 72 @Override
65 public void connect() throws IOException { 73 public void connect() throws IOException {
66 if (connected) { 74 startRequest(true);
67 checkHasResponse();
68 return;
69 }
70 connected = true;
71 for (Pair<String, String> requestHeader : mRequestHeaders) {
72 mRequest.addHeader(requestHeader.first, requestHeader.second);
73 }
74 if (!getUseCaches()) {
75 mRequest.disableCache();
76 }
77 mRequest.start();
78 // Blocks until onResponseStarted or onFailed is called.
79 mMessageLoop.loop();
80 checkHasResponse();
81 } 75 }
82 76
83 /** 77 /**
84 * Releases this connection so that its resources may be either reused or 78 * Releases this connection so that its resources may be either reused or
85 * closed. 79 * closed.
86 */ 80 */
87 @Override 81 @Override
88 public void disconnect() { 82 public void disconnect() {
89 // Disconnect before connection is made should have no effect. 83 // Disconnect before connection is made should have no effect.
90 if (connected) { 84 if (connected) {
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after
191 throw new IOException("Cannot read response body of a redirect."); 185 throw new IOException("Cannot read response body of a redirect.");
192 } 186 }
193 // Emulate default implementation's behavior to throw 187 // Emulate default implementation's behavior to throw
194 // FileNotFoundException when we get a 400 and above. 188 // FileNotFoundException when we get a 400 and above.
195 if (mResponseInfo.getHttpStatusCode() >= HTTP_BAD_REQUEST) { 189 if (mResponseInfo.getHttpStatusCode() >= HTTP_BAD_REQUEST) {
196 throw new FileNotFoundException(url.toString()); 190 throw new FileNotFoundException(url.toString());
197 } 191 }
198 return mInputStream; 192 return mInputStream;
199 } 193 }
200 194
195 @Override
196 public OutputStream getOutputStream() throws IOException {
197 if (mOutputStream == null) {
198 if (connected) {
199 throw new ProtocolException(
200 "Cannot write to OutputStream after receiving response." );
201 }
202 boolean bufferRequestBody = false;
pauljensen 2015/03/04 16:44:10 dead?
xunjieli 2015/03/05 17:43:10 Done.
203 if (mFixedContentLength != -1) {
204 addRequestProperty("Content-Length",
205 Long.toString(mFixedContentLength));
206 mOutputStream = new CronetOutputStream(this, mFixedContentLength );
207 } else {
208 bufferRequestBody = true;
pauljensen 2015/03/04 16:44:10 dead?
xunjieli 2015/03/05 17:43:11 Done.
209 Log.d(TAG, "Outputstream is being buffered in memory.");
210 String length = getRequestProperty("Content-Length");
211 if (length == null) {
212 mOutputStream = new CronetBufferedOutputStream(this, -1);
213 } else {
214 long lengthParsed = Long.parseLong(length);
215 mOutputStream = new CronetBufferedOutputStream(this, lengthP arsed);
216 }
217 return mOutputStream;
218 }
219 }
220 startRequest(false);
221 return mOutputStream;
222 }
223
224 /**
225 * Starts the request if {@code connected} is false. If {@code readResponse}
226 * is true, block until the response is received.
227 */
228 private void startRequest(boolean readResponse) throws IOException {
229 if (connected) {
230 if (readResponse) {
231 checkHasResponse();
232 }
233 return;
234 }
235 if (mOutputStream != null) {
236 // Default Content-Type to application/x-www-form-urlencoded
237 if (getRequestProperty("Content-Type") == null) {
238 addRequestProperty("Content-Type",
239 "application/x-www-form-urlencoded");
240 }
241 mRequest.setUploadDataProvider((UploadDataProvider) mOutputStream,
242 mMessageLoop);
243 }
244 connected = true;
245 // Start the request. Note that connect() is not used since
246 // connect() blocks until headers are received.
247 for (Pair<String, String> requestHeader : mRequestHeaders) {
248 mRequest.addHeader(requestHeader.first, requestHeader.second);
249 }
250 if (!getUseCaches()) {
251 mRequest.disableCache();
252 }
253 mRequest.start();
254 if (readResponse) {
255 // Blocks until onResponseStarted or onFailed is called.
256 mMessageLoop.loop();
257 checkHasResponse();
258 }
259 }
260
201 /** 261 /**
202 * Returns an input stream from the server in the case of an error such as 262 * Returns an input stream from the server in the case of an error such as
203 * the requested file has not been found on the remote server. 263 * the requested file has not been found on the remote server.
204 */ 264 */
205 @Override 265 @Override
206 public InputStream getErrorStream() { 266 public InputStream getErrorStream() {
207 try { 267 try {
208 connect(); 268 connect();
209 } catch (IOException e) { 269 } catch (IOException e) {
210 return null; 270 return null;
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
294 /** 354 /**
295 * Returns whether this connection uses a proxy server. 355 * Returns whether this connection uses a proxy server.
296 */ 356 */
297 @Override 357 @Override
298 public boolean usingProxy() { 358 public boolean usingProxy() {
299 // TODO(xunjieli): implement this. 359 // TODO(xunjieli): implement this.
300 return false; 360 return false;
301 } 361 }
302 362
303 /** 363 /**
364 * Sets chunked streaming mode.
365 */
366 @Override
367 public void setChunkedStreamingMode(int chunklen) {
368 // TODO(xunjieli): implement this.
369 throw new UnsupportedOperationException("Chunked mode not supported yet" );
370 }
371
372 @Override
373 public void setFixedLengthStreamingMode(int contentLength) {
374 setFixedLengthStreamingMode((long) contentLength);
375 }
376
377 @Override
378 public void setFixedLengthStreamingMode(long contentLength) {
379 if (connected) {
380 throw new IllegalStateException("Already connected");
381 }
382 if (chunkLength > 0) {
383 throw new IllegalStateException("Already in chunked mode");
384 }
385 if (contentLength < 0) {
386 throw new IllegalArgumentException("contentLength < 0");
387 }
388 mFixedContentLength = contentLength;
389 super.fixedContentLength = (int) Math.min(contentLength, Integer.MAX_VAL UE);
pauljensen 2015/03/04 16:44:11 Should this set super.fixedContentLengthLong? or m
xunjieli 2015/03/05 17:43:10 Done. this long version exists only since Jdk 1.7.
390 }
391
392 /**
304 * Used by {@link CronetInputStream} to get more data from the network 393 * Used by {@link CronetInputStream} to get more data from the network
305 * stack. This should only be called after the request has started. Note 394 * stack. This should only be called after the request has started. Note
306 * that this call might block if there isn't any more data to be read. 395 * that this call might block if there isn't any more data to be read.
307 */ 396 */
308 ByteBuffer getMoreData() throws IOException { 397 ByteBuffer getMoreData() throws IOException {
309 mResponseByteBuffer = null; 398 mResponseByteBuffer = null;
310 mMessageLoop.loop(); 399 mMessageLoop.loop();
311 return mResponseByteBuffer; 400 return mResponseByteBuffer;
312 } 401 }
313 402
314 /** 403 /**
404 * Used by {@link CronetOutputStream} to wait for data consumed by the
405 * network stack before writing more data.
406 */
407 void waitForPostDataConsumed() throws IOException {
408 mMessageLoop.loop();
409 }
410
411 /**
412 * Used by {@link CronetOutputStream.CronetUploadDataProvider} to wait for
pauljensen 2015/03/04 16:44:11 What is CronetOutputStream.CronetUploadDataProvide
xunjieli 2015/03/05 17:43:10 Done. Sorry, forgot to update the comment.
413 * embedder to provide more data.
414 */
415 void waitForPostData() {
416 mMessageLoop.postQuitTask();
417 }
418
419 /**
315 * Returns the index of request header in {@link #mRequestHeaders} or 420 * Returns the index of request header in {@link #mRequestHeaders} or
316 * -1 if not found. 421 * -1 if not found.
317 */ 422 */
318 private int findRequestProperty(String key) { 423 private int findRequestProperty(String key) {
319 for (int i = 0; i < mRequestHeaders.size(); i++) { 424 for (int i = 0; i < mRequestHeaders.size(); i++) {
320 Pair<String, String> entry = mRequestHeaders.get(i); 425 Pair<String, String> entry = mRequestHeaders.get(i);
321 if (entry.first.equalsIgnoreCase(key)) { 426 if (entry.first.equalsIgnoreCase(key)) {
322 return i; 427 return i;
323 } 428 }
324 } 429 }
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
417 return null; 522 return null;
418 } 523 }
419 List<Pair<String, String>> headers = 524 List<Pair<String, String>> headers =
420 mResponseInfo.getAllHeadersAsList(); 525 mResponseInfo.getAllHeadersAsList();
421 if (pos >= headers.size()) { 526 if (pos >= headers.size()) {
422 return null; 527 return null;
423 } 528 }
424 return headers.get(pos); 529 return headers.get(pos);
425 } 530 }
426 } 531 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698