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

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

Issue 1359343005: Update ResponseInfo to UrlResponseInfo with API review comments. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase to CronetEngine builders. Created 5 years, 2 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; 5 package org.chromium.net;
6 6
7 import android.util.Log; 7 import android.util.Log;
8 import android.util.Pair;
9 8
10 import org.chromium.base.VisibleForTesting; 9 import org.chromium.base.VisibleForTesting;
11 import org.chromium.base.annotations.CalledByNative; 10 import org.chromium.base.annotations.CalledByNative;
12 import org.chromium.base.annotations.JNIAdditionalImport; 11 import org.chromium.base.annotations.JNIAdditionalImport;
13 import org.chromium.base.annotations.JNINamespace; 12 import org.chromium.base.annotations.JNINamespace;
14 import org.chromium.base.annotations.NativeClassQualifiedName; 13 import org.chromium.base.annotations.NativeClassQualifiedName;
15 14
16 import java.nio.ByteBuffer; 15 import java.nio.ByteBuffer;
16 import java.util.AbstractMap;
17 import java.util.ArrayList; 17 import java.util.ArrayList;
18 import java.util.Collections;
19 import java.util.List; 18 import java.util.List;
20 import java.util.Map; 19 import java.util.Map;
21 import java.util.TreeMap;
22 import java.util.concurrent.Executor; 20 import java.util.concurrent.Executor;
23 import java.util.concurrent.RejectedExecutionException; 21 import java.util.concurrent.RejectedExecutionException;
24 22
25 /** 23 /**
26 * UrlRequest using Chromium HTTP stack implementation. Could be accessed from 24 * UrlRequest using Chromium HTTP stack implementation. Could be accessed from
27 * any thread on Executor. Cancel can be called from any thread. 25 * any thread on Executor. Cancel can be called from any thread.
28 * All @CallByNative methods are called on native network thread 26 * All @CallByNative methods are called on native network thread
29 * and post tasks with listener calls onto Executor. Upon return from listener 27 * and post tasks with listener calls onto Executor. Upon return from listener
30 * callback native request adapter is called on executive thread and posts 28 * callback native request adapter is called on executive thread and posts
31 * native tasks to native network thread. Because Cancel could be called from 29 * native tasks to native network thread. Because Cancel could be called from
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
66 private final List<String> mUrlChain = new ArrayList<String>(); 64 private final List<String> mUrlChain = new ArrayList<String>();
67 65
68 private final UrlRequestListener mListener; 66 private final UrlRequestListener mListener;
69 private final String mInitialUrl; 67 private final String mInitialUrl;
70 private final int mPriority; 68 private final int mPriority;
71 private String mInitialMethod; 69 private String mInitialMethod;
72 private final HeadersList mRequestHeaders = new HeadersList(); 70 private final HeadersList mRequestHeaders = new HeadersList();
73 71
74 private CronetUploadDataStream mUploadDataStream; 72 private CronetUploadDataStream mUploadDataStream;
75 73
76 private NativeResponseInfo mResponseInfo; 74 private UrlResponseInfo mResponseInfo;
77 75
78 /* 76 /*
79 * Listener callback is repeatedly called when each read is completed, so it 77 * Listener callback is repeatedly called when each read is completed, so it
80 * is cached as a member variable. 78 * is cached as a member variable.
81 */ 79 */
82 private OnReadCompletedRunnable mOnReadCompletedTask; 80 private OnReadCompletedRunnable mOnReadCompletedTask;
83 81
84 private Runnable mOnDestroyedCallbackForTests; 82 private Runnable mOnDestroyedCallbackForTests;
85 83
86 private static final class HeadersList extends ArrayList<Pair<String, String >> {} 84 private static final class HeadersList extends ArrayList<Map.Entry<String, S tring>> {}
87 85
88 private final class OnReadCompletedRunnable implements Runnable { 86 private final class OnReadCompletedRunnable implements Runnable {
89 ByteBuffer mByteBuffer; 87 ByteBuffer mByteBuffer;
90 88
91 @Override 89 @Override
92 public void run() { 90 public void run() {
93 if (isDone()) { 91 if (isDone()) {
94 return; 92 return;
95 } 93 }
96 try { 94 try {
97 synchronized (mUrlRequestAdapterLock) { 95 synchronized (mUrlRequestAdapterLock) {
98 if (mUrlRequestAdapter == 0) { 96 if (mUrlRequestAdapter == 0) {
99 return; 97 return;
100 } 98 }
101 mWaitingOnRead = true; 99 mWaitingOnRead = true;
102 } 100 }
103 // Null out mByteBuffer, out of paranoia. Has to be done before 101 // Null out mByteBuffer, out of paranoia. Has to be done before
104 // mListener call, to avoid any race when there are multiple 102 // mListener call, to avoid any race when there are multiple
105 // executor threads. 103 // executor threads.
106 ByteBuffer buffer = mByteBuffer; 104 ByteBuffer buffer = mByteBuffer;
107 mByteBuffer = null; 105 mByteBuffer = null;
108 mListener.onReadCompleted(CronetUrlRequest.this, 106 mListener.onReadCompleted(CronetUrlRequest.this,
109 mResponseInfo, buffer); 107 mResponseInfo, buffer);
110 } catch (Exception e) { 108 } catch (Exception e) {
111 onListenerException(e); 109 onListenerException(e);
112 } 110 }
113 } 111 }
114 } 112 }
115 113
116 private static final class NativeResponseInfo implements ResponseInfo {
117 private final String[] mResponseInfoUrlChain;
118 private final int mHttpStatusCode;
119 private final String mHttpStatusText;
120 private final boolean mWasCached;
121 private final String mNegotiatedProtocol;
122 private final String mProxyServer;
123 private final HeadersList mAllHeaders = new HeadersList();
124 private Map<String, List<String>> mResponseHeaders;
125 private List<Pair<String, String>> mUnmodifiableAllHeaders;
126
127 NativeResponseInfo(String[] urlChain, int httpStatusCode,
128 String httpStatusText, boolean wasCached,
129 String negotiatedProtocol, String proxyServer) {
130 mResponseInfoUrlChain = urlChain;
131 mHttpStatusCode = httpStatusCode;
132 mHttpStatusText = httpStatusText;
133 mWasCached = wasCached;
134 mNegotiatedProtocol = negotiatedProtocol;
135 mProxyServer = proxyServer;
136 }
137
138 @Override
139 public String getUrl() {
140 return mResponseInfoUrlChain[mResponseInfoUrlChain.length - 1];
141 }
142
143 @Override
144 public String[] getUrlChain() {
145 return mResponseInfoUrlChain;
146 }
147
148 @Override
149 public int getHttpStatusCode() {
150 return mHttpStatusCode;
151 }
152
153 @Override
154 public String getHttpStatusText() {
155 return mHttpStatusText;
156 }
157
158 @Override
159 public List<Pair<String, String>> getAllHeadersAsList() {
160 if (mUnmodifiableAllHeaders == null) {
161 mUnmodifiableAllHeaders =
162 Collections.unmodifiableList(mAllHeaders);
163 }
164 return mUnmodifiableAllHeaders;
165 }
166
167 @Override
168 public Map<String, List<String>> getAllHeaders() {
169 if (mResponseHeaders != null) {
170 return mResponseHeaders;
171 }
172 Map<String, List<String>> map = new TreeMap<String, List<String>>(
173 String.CASE_INSENSITIVE_ORDER);
174 for (Pair<String, String> entry : mAllHeaders) {
175 List<String> values = new ArrayList<String>();
176 if (map.containsKey(entry.first)) {
177 values.addAll(map.get(entry.first));
178 }
179 values.add(entry.second);
180 map.put(entry.first, Collections.unmodifiableList(values));
181 }
182 mResponseHeaders = Collections.unmodifiableMap(map);
183 return mResponseHeaders;
184 }
185
186 @Override
187 public boolean wasCached() {
188 return mWasCached;
189 }
190
191 @Override
192 public String getNegotiatedProtocol() {
193 return mNegotiatedProtocol;
194 }
195
196 @Override
197 public String getProxyServer() {
198 return mProxyServer;
199 }
200 };
201
202 private static final class NativeExtendedResponseInfo implements ExtendedRes ponseInfo {
203 private final ResponseInfo mResponseInfo;
204 private final long mTotalReceivedBytes;
205
206 NativeExtendedResponseInfo(ResponseInfo responseInfo,
207 long totalReceivedBytes) {
208 mResponseInfo = responseInfo;
209 mTotalReceivedBytes = totalReceivedBytes;
210 }
211
212 @Override
213 public ResponseInfo getResponseInfo() {
214 return mResponseInfo;
215 }
216
217 @Override
218 public long getTotalReceivedBytes() {
219 return mTotalReceivedBytes;
220 }
221 };
222
223 CronetUrlRequest(CronetUrlRequestContext requestContext, 114 CronetUrlRequest(CronetUrlRequestContext requestContext,
224 long urlRequestContextAdapter, 115 long urlRequestContextAdapter,
225 String url, 116 String url,
226 int priority, 117 int priority,
227 UrlRequestListener listener, 118 UrlRequestListener listener,
228 Executor executor) { 119 Executor executor) {
229 if (url == null) { 120 if (url == null) {
230 throw new NullPointerException("URL is required"); 121 throw new NullPointerException("URL is required");
231 } 122 }
232 if (listener == null) { 123 if (listener == null) {
(...skipping 22 matching lines...) Expand all
255 146
256 @Override 147 @Override
257 public void addHeader(String header, String value) { 148 public void addHeader(String header, String value) {
258 checkNotStarted(); 149 checkNotStarted();
259 if (header == null) { 150 if (header == null) {
260 throw new NullPointerException("Invalid header name."); 151 throw new NullPointerException("Invalid header name.");
261 } 152 }
262 if (value == null) { 153 if (value == null) {
263 throw new NullPointerException("Invalid header value."); 154 throw new NullPointerException("Invalid header value.");
264 } 155 }
265 mRequestHeaders.add(Pair.create(header, value)); 156 mRequestHeaders.add(new AbstractMap.SimpleImmutableEntry<String, String> (header, value));
266 } 157 }
267 158
268 @Override 159 @Override
269 public void setUploadDataProvider(UploadDataProvider uploadDataProvider, Exe cutor executor) { 160 public void setUploadDataProvider(UploadDataProvider uploadDataProvider, Exe cutor executor) {
270 if (uploadDataProvider == null) { 161 if (uploadDataProvider == null) {
271 throw new NullPointerException("Invalid UploadDataProvider."); 162 throw new NullPointerException("Invalid UploadDataProvider.");
272 } 163 }
273 if (mInitialMethod == null) { 164 if (mInitialMethod == null) {
274 mInitialMethod = "POST"; 165 mInitialMethod = "POST";
275 } 166 }
276 mUploadDataStream = new CronetUploadDataStream(uploadDataProvider, execu tor); 167 mUploadDataStream = new CronetUploadDataStream(uploadDataProvider, execu tor);
277 } 168 }
278 169
279 @Override 170 @Override
280 public void start() { 171 public void start() {
281 synchronized (mUrlRequestAdapterLock) { 172 synchronized (mUrlRequestAdapterLock) {
282 checkNotStarted(); 173 checkNotStarted();
283 174
284 try { 175 try {
285 mUrlRequestAdapter = nativeCreateRequestAdapter( 176 mUrlRequestAdapter = nativeCreateRequestAdapter(
286 mRequestContext.getUrlRequestContextAdapter(), mInitialU rl, mPriority); 177 mRequestContext.getUrlRequestContextAdapter(), mInitialU rl, mPriority);
287 mRequestContext.onRequestStarted(this); 178 mRequestContext.onRequestStarted(this);
288 if (mInitialMethod != null) { 179 if (mInitialMethod != null) {
289 if (!nativeSetHttpMethod(mUrlRequestAdapter, mInitialMethod) ) { 180 if (!nativeSetHttpMethod(mUrlRequestAdapter, mInitialMethod) ) {
290 throw new IllegalArgumentException("Invalid http method " + mInitialMethod); 181 throw new IllegalArgumentException("Invalid http method " + mInitialMethod);
291 } 182 }
292 } 183 }
293 184
294 boolean hasContentType = false; 185 boolean hasContentType = false;
295 for (Pair<String, String> header : mRequestHeaders) { 186 for (Map.Entry<String, String> header : mRequestHeaders) {
296 if (header.first.equalsIgnoreCase("Content-Type") 187 if (header.getKey().equalsIgnoreCase("Content-Type")
297 && !header.second.isEmpty()) { 188 && !header.getValue().isEmpty()) {
298 hasContentType = true; 189 hasContentType = true;
299 } 190 }
300 if (!nativeAddRequestHeader(mUrlRequestAdapter, header.first , header.second)) { 191 if (!nativeAddRequestHeader(
192 mUrlRequestAdapter, header.getKey(), header.getV alue())) {
301 destroyRequestAdapter(); 193 destroyRequestAdapter();
302 throw new IllegalArgumentException( 194 throw new IllegalArgumentException(
303 "Invalid header " + header.first + "=" + header. second); 195 "Invalid header " + header.getKey() + "=" + head er.getValue());
304 } 196 }
305 } 197 }
306 if (mUploadDataStream != null) { 198 if (mUploadDataStream != null) {
307 if (!hasContentType) { 199 if (!hasContentType) {
308 throw new IllegalArgumentException( 200 throw new IllegalArgumentException(
309 "Requests with upload data must have a Content-T ype."); 201 "Requests with upload data must have a Content-T ype.");
310 } 202 }
311 mUploadDataStream.attachToRequest(this, mUrlRequestAdapter); 203 mUploadDataStream.attachToRequest(this, mUrlRequestAdapter);
312 } 204 }
313 } catch (RuntimeException e) { 205 } catch (RuntimeException e) {
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after
474 return RequestPriority.LOW; 366 return RequestPriority.LOW;
475 case Builder.REQUEST_PRIORITY_MEDIUM: 367 case Builder.REQUEST_PRIORITY_MEDIUM:
476 return RequestPriority.MEDIUM; 368 return RequestPriority.MEDIUM;
477 case Builder.REQUEST_PRIORITY_HIGHEST: 369 case Builder.REQUEST_PRIORITY_HIGHEST:
478 return RequestPriority.HIGHEST; 370 return RequestPriority.HIGHEST;
479 default: 371 default:
480 return RequestPriority.MEDIUM; 372 return RequestPriority.MEDIUM;
481 } 373 }
482 } 374 }
483 375
484 private NativeResponseInfo prepareResponseInfoOnNetworkThread( 376 private UrlResponseInfo prepareResponseInfoOnNetworkThread(int httpStatusCod e) {
485 int httpStatusCode) {
486 long urlRequestAdapter; 377 long urlRequestAdapter;
487 synchronized (mUrlRequestAdapterLock) { 378 synchronized (mUrlRequestAdapterLock) {
488 if (mUrlRequestAdapter == 0) { 379 if (mUrlRequestAdapter == 0) {
489 return null; 380 return null;
490 } 381 }
491 // This method is running on network thread, so even if 382 // This method is running on network thread, so even if
492 // mUrlRequestAdapter is set to 0 from another thread the actual 383 // mUrlRequestAdapter is set to 0 from another thread the actual
493 // deletion of the adapter is posted to network thread, so it is 384 // deletion of the adapter is posted to network thread, so it is
494 // safe to preserve and use urlRequestAdapter outside the lock. 385 // safe to preserve and use urlRequestAdapter outside the lock.
495 urlRequestAdapter = mUrlRequestAdapter; 386 urlRequestAdapter = mUrlRequestAdapter;
496 } 387 }
497 NativeResponseInfo responseInfo = new NativeResponseInfo( 388 HeadersList headersList = new HeadersList();
498 mUrlChain.toArray(new String[mUrlChain.size()]), 389 nativePopulateResponseHeaders(urlRequestAdapter, headersList);
499 httpStatusCode, 390
500 nativeGetHttpStatusText(urlRequestAdapter), 391 UrlResponseInfo responseInfo = new UrlResponseInfo(new ArrayList<String> (mUrlChain),
392 httpStatusCode, nativeGetHttpStatusText(urlRequestAdapter), head ersList,
501 nativeGetWasCached(urlRequestAdapter), 393 nativeGetWasCached(urlRequestAdapter),
502 nativeGetNegotiatedProtocol(urlRequestAdapter), 394 nativeGetNegotiatedProtocol(urlRequestAdapter),
503 nativeGetProxyServer(urlRequestAdapter)); 395 nativeGetProxyServer(urlRequestAdapter));
504 nativePopulateResponseHeaders(urlRequestAdapter,
505 responseInfo.mAllHeaders);
506 return responseInfo; 396 return responseInfo;
507 } 397 }
508 398
509 private void checkNotStarted() { 399 private void checkNotStarted() {
510 synchronized (mUrlRequestAdapterLock) { 400 synchronized (mUrlRequestAdapterLock) {
511 if (mStarted || isDone()) { 401 if (mStarted || isDone()) {
512 throw new IllegalStateException("Request is already started."); 402 throw new IllegalStateException("Request is already started.");
513 } 403 }
514 } 404 }
515 } 405 }
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
599 * callback. If the redirect response has a body, it will be ignored. 489 * callback. If the redirect response has a body, it will be ignored.
600 * This will only be called between start and onResponseStarted. 490 * This will only be called between start and onResponseStarted.
601 * 491 *
602 * @param newLocation Location where request is redirected. 492 * @param newLocation Location where request is redirected.
603 * @param httpStatusCode from redirect response 493 * @param httpStatusCode from redirect response
604 */ 494 */
605 @SuppressWarnings("unused") 495 @SuppressWarnings("unused")
606 @CalledByNative 496 @CalledByNative
607 private void onReceivedRedirect(final String newLocation, 497 private void onReceivedRedirect(final String newLocation,
608 int httpStatusCode) { 498 int httpStatusCode) {
609 final NativeResponseInfo responseInfo = 499 final UrlResponseInfo responseInfo = prepareResponseInfoOnNetworkThread( httpStatusCode);
610 prepareResponseInfoOnNetworkThread(httpStatusCode);
611 // Have to do this after creating responseInfo. 500 // Have to do this after creating responseInfo.
612 mUrlChain.add(newLocation); 501 mUrlChain.add(newLocation);
613 502
614 Runnable task = new Runnable() { 503 Runnable task = new Runnable() {
615 public void run() { 504 public void run() {
616 synchronized (mUrlRequestAdapterLock) { 505 synchronized (mUrlRequestAdapterLock) {
617 if (isDone()) { 506 if (isDone()) {
618 return; 507 return;
619 } 508 }
620 mWaitingOnRedirect = true; 509 mWaitingOnRedirect = true;
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
694 postTaskToExecutor(mOnReadCompletedTask); 583 postTaskToExecutor(mOnReadCompletedTask);
695 } 584 }
696 585
697 /** 586 /**
698 * Called when request is completed successfully, no callbacks will be 587 * Called when request is completed successfully, no callbacks will be
699 * called afterwards. 588 * called afterwards.
700 */ 589 */
701 @SuppressWarnings("unused") 590 @SuppressWarnings("unused")
702 @CalledByNative 591 @CalledByNative
703 private void onSucceeded(long totalReceivedBytes) { 592 private void onSucceeded(long totalReceivedBytes) {
704 final NativeExtendedResponseInfo extendedResponseInfo = 593 mResponseInfo.setReceivedBytesCount(totalReceivedBytes);
705 new NativeExtendedResponseInfo(mResponseInfo,
706 totalReceivedBytes);
707 Runnable task = new Runnable() { 594 Runnable task = new Runnable() {
708 public void run() { 595 public void run() {
709 synchronized (mUrlRequestAdapterLock) { 596 synchronized (mUrlRequestAdapterLock) {
710 if (isDone()) { 597 if (isDone()) {
711 return; 598 return;
712 } 599 }
713 // Destroy adapter first, so request context could be shut 600 // Destroy adapter first, so request context could be shut
714 // down from the listener. 601 // down from the listener.
715 destroyRequestAdapter(); 602 destroyRequestAdapter();
716 } 603 }
717 try { 604 try {
718 mListener.onSucceeded(CronetUrlRequest.this, 605 mListener.onSucceeded(CronetUrlRequest.this, mResponseInfo);
719 extendedResponseInfo);
720 } catch (Exception e) { 606 } catch (Exception e) {
721 Log.e(CronetUrlRequestContext.LOG_TAG, 607 Log.e(CronetUrlRequestContext.LOG_TAG,
722 "Exception in onComplete method", e); 608 "Exception in onComplete method", e);
723 } 609 }
724 } 610 }
725 }; 611 };
726 postTaskToExecutor(task); 612 postTaskToExecutor(task);
727 } 613 }
728 614
729 /** 615 /**
(...skipping 11 matching lines...) Expand all
741 failWithException(requestError); 627 failWithException(requestError);
742 } 628 }
743 629
744 /** 630 /**
745 * Appends header |name| with value |value| to |headersList|. 631 * Appends header |name| with value |value| to |headersList|.
746 */ 632 */
747 @SuppressWarnings("unused") 633 @SuppressWarnings("unused")
748 @CalledByNative 634 @CalledByNative
749 private void onAppendResponseHeader(HeadersList headersList, 635 private void onAppendResponseHeader(HeadersList headersList,
750 String name, String value) { 636 String name, String value) {
751 headersList.add(Pair.create(name, value)); 637 headersList.add(new AbstractMap.SimpleImmutableEntry<String, String>(nam e, value));
752 } 638 }
753 639
754 /** 640 /**
755 * Called by the native code when request status is fetched from the 641 * Called by the native code when request status is fetched from the
756 * native stack. 642 * native stack.
757 */ 643 */
758 @SuppressWarnings("unused") 644 @SuppressWarnings("unused")
759 @CalledByNative 645 @CalledByNative
760 private void onStatus(final UrlRequest.StatusListener listener, final int lo adState) { 646 private void onStatus(final UrlRequest.StatusListener listener, final int lo adState) {
761 Runnable task = new Runnable() { 647 Runnable task = new Runnable() {
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
805 691
806 @NativeClassQualifiedName("CronetURLRequestAdapter") 692 @NativeClassQualifiedName("CronetURLRequestAdapter")
807 private native String nativeGetProxyServer(long nativePtr); 693 private native String nativeGetProxyServer(long nativePtr);
808 694
809 @NativeClassQualifiedName("CronetURLRequestAdapter") 695 @NativeClassQualifiedName("CronetURLRequestAdapter")
810 private native void nativeGetStatus(long nativePtr, UrlRequest.StatusListene r listener); 696 private native void nativeGetStatus(long nativePtr, UrlRequest.StatusListene r listener);
811 697
812 @NativeClassQualifiedName("CronetURLRequestAdapter") 698 @NativeClassQualifiedName("CronetURLRequestAdapter")
813 private native boolean nativeGetWasCached(long nativePtr); 699 private native boolean nativeGetWasCached(long nativePtr);
814 } 700 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698