OLD | NEW |
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 25 matching lines...) Expand all Loading... |
57 private final Object mUrlRequestAdapterLock = new Object(); | 55 private final Object mUrlRequestAdapterLock = new Object(); |
58 private final CronetUrlRequestContext mRequestContext; | 56 private final CronetUrlRequestContext mRequestContext; |
59 private final Executor mExecutor; | 57 private final Executor mExecutor; |
60 | 58 |
61 /* | 59 /* |
62 * URL chain contains the URL currently being requested, and | 60 * URL chain contains the URL currently being requested, and |
63 * all URLs previously requested. New URLs are added before | 61 * all URLs previously requested. New URLs are added before |
64 * mListener.onReceivedRedirect is called. | 62 * mListener.onReceivedRedirect is called. |
65 */ | 63 */ |
66 private final List<String> mUrlChain = new ArrayList<String>(); | 64 private final List<String> mUrlChain = new ArrayList<String>(); |
| 65 private long mReceivedBytesCountFromRedirects; |
67 | 66 |
68 private final UrlRequestListener mListener; | 67 private final UrlRequestListener mListener; |
69 private final String mInitialUrl; | 68 private final String mInitialUrl; |
70 private final int mPriority; | 69 private final int mPriority; |
71 private String mInitialMethod; | 70 private String mInitialMethod; |
72 private final HeadersList mRequestHeaders = new HeadersList(); | 71 private final HeadersList mRequestHeaders = new HeadersList(); |
73 | 72 |
74 private CronetUploadDataStream mUploadDataStream; | 73 private CronetUploadDataStream mUploadDataStream; |
75 | 74 |
76 private NativeResponseInfo mResponseInfo; | 75 private UrlResponseInfo mResponseInfo; |
77 | 76 |
78 /* | 77 /* |
79 * Listener callback is repeatedly called when each read is completed, so it | 78 * Listener callback is repeatedly called when each read is completed, so it |
80 * is cached as a member variable. | 79 * is cached as a member variable. |
81 */ | 80 */ |
82 private OnReadCompletedRunnable mOnReadCompletedTask; | 81 private OnReadCompletedRunnable mOnReadCompletedTask; |
83 | 82 |
84 private Runnable mOnDestroyedCallbackForTests; | 83 private Runnable mOnDestroyedCallbackForTests; |
85 | 84 |
86 private static final class HeadersList extends ArrayList<Pair<String, String
>> {} | 85 private static final class HeadersList extends ArrayList<Map.Entry<String, S
tring>> {} |
87 | 86 |
88 private final class OnReadCompletedRunnable implements Runnable { | 87 private final class OnReadCompletedRunnable implements Runnable { |
89 ByteBuffer mByteBuffer; | 88 ByteBuffer mByteBuffer; |
90 | 89 |
91 @Override | 90 @Override |
92 public void run() { | 91 public void run() { |
93 if (isDone()) { | 92 if (isDone()) { |
94 return; | 93 return; |
95 } | 94 } |
96 try { | 95 try { |
97 synchronized (mUrlRequestAdapterLock) { | 96 synchronized (mUrlRequestAdapterLock) { |
98 if (mUrlRequestAdapter == 0) { | 97 if (mUrlRequestAdapter == 0) { |
99 return; | 98 return; |
100 } | 99 } |
101 mWaitingOnRead = true; | 100 mWaitingOnRead = true; |
102 } | 101 } |
103 // Null out mByteBuffer, out of paranoia. Has to be done before | 102 // Null out mByteBuffer, out of paranoia. Has to be done before |
104 // mListener call, to avoid any race when there are multiple | 103 // mListener call, to avoid any race when there are multiple |
105 // executor threads. | 104 // executor threads. |
106 ByteBuffer buffer = mByteBuffer; | 105 ByteBuffer buffer = mByteBuffer; |
107 mByteBuffer = null; | 106 mByteBuffer = null; |
108 mListener.onReadCompleted(CronetUrlRequest.this, | 107 mListener.onReadCompleted(CronetUrlRequest.this, |
109 mResponseInfo, buffer); | 108 mResponseInfo, buffer); |
110 } catch (Exception e) { | 109 } catch (Exception e) { |
111 onListenerException(e); | 110 onListenerException(e); |
112 } | 111 } |
113 } | 112 } |
114 } | 113 } |
115 | 114 |
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, | 115 CronetUrlRequest(CronetUrlRequestContext requestContext, |
224 long urlRequestContextAdapter, | 116 long urlRequestContextAdapter, |
225 String url, | 117 String url, |
226 int priority, | 118 int priority, |
227 UrlRequestListener listener, | 119 UrlRequestListener listener, |
228 Executor executor) { | 120 Executor executor) { |
229 if (url == null) { | 121 if (url == null) { |
230 throw new NullPointerException("URL is required"); | 122 throw new NullPointerException("URL is required"); |
231 } | 123 } |
232 if (listener == null) { | 124 if (listener == null) { |
(...skipping 22 matching lines...) Expand all Loading... |
255 | 147 |
256 @Override | 148 @Override |
257 public void addHeader(String header, String value) { | 149 public void addHeader(String header, String value) { |
258 checkNotStarted(); | 150 checkNotStarted(); |
259 if (header == null) { | 151 if (header == null) { |
260 throw new NullPointerException("Invalid header name."); | 152 throw new NullPointerException("Invalid header name."); |
261 } | 153 } |
262 if (value == null) { | 154 if (value == null) { |
263 throw new NullPointerException("Invalid header value."); | 155 throw new NullPointerException("Invalid header value."); |
264 } | 156 } |
265 mRequestHeaders.add(Pair.create(header, value)); | 157 mRequestHeaders.add(new AbstractMap.SimpleImmutableEntry<String, String>
(header, value)); |
266 } | 158 } |
267 | 159 |
268 @Override | 160 @Override |
269 public void setUploadDataProvider(UploadDataProvider uploadDataProvider, Exe
cutor executor) { | 161 public void setUploadDataProvider(UploadDataProvider uploadDataProvider, Exe
cutor executor) { |
270 if (uploadDataProvider == null) { | 162 if (uploadDataProvider == null) { |
271 throw new NullPointerException("Invalid UploadDataProvider."); | 163 throw new NullPointerException("Invalid UploadDataProvider."); |
272 } | 164 } |
273 if (mInitialMethod == null) { | 165 if (mInitialMethod == null) { |
274 mInitialMethod = "POST"; | 166 mInitialMethod = "POST"; |
275 } | 167 } |
276 mUploadDataStream = new CronetUploadDataStream(uploadDataProvider, execu
tor); | 168 mUploadDataStream = new CronetUploadDataStream(uploadDataProvider, execu
tor); |
277 } | 169 } |
278 | 170 |
279 @Override | 171 @Override |
280 public void start() { | 172 public void start() { |
281 synchronized (mUrlRequestAdapterLock) { | 173 synchronized (mUrlRequestAdapterLock) { |
282 checkNotStarted(); | 174 checkNotStarted(); |
283 | 175 |
284 try { | 176 try { |
285 mUrlRequestAdapter = nativeCreateRequestAdapter( | 177 mUrlRequestAdapter = nativeCreateRequestAdapter( |
286 mRequestContext.getUrlRequestContextAdapter(), mInitialU
rl, mPriority); | 178 mRequestContext.getUrlRequestContextAdapter(), mInitialU
rl, mPriority); |
287 mRequestContext.onRequestStarted(this); | 179 mRequestContext.onRequestStarted(this); |
288 if (mInitialMethod != null) { | 180 if (mInitialMethod != null) { |
289 if (!nativeSetHttpMethod(mUrlRequestAdapter, mInitialMethod)
) { | 181 if (!nativeSetHttpMethod(mUrlRequestAdapter, mInitialMethod)
) { |
290 throw new IllegalArgumentException("Invalid http method
" + mInitialMethod); | 182 throw new IllegalArgumentException("Invalid http method
" + mInitialMethod); |
291 } | 183 } |
292 } | 184 } |
293 | 185 |
294 boolean hasContentType = false; | 186 boolean hasContentType = false; |
295 for (Pair<String, String> header : mRequestHeaders) { | 187 for (Map.Entry<String, String> header : mRequestHeaders) { |
296 if (header.first.equalsIgnoreCase("Content-Type") | 188 if (header.getKey().equalsIgnoreCase("Content-Type") |
297 && !header.second.isEmpty()) { | 189 && !header.getValue().isEmpty()) { |
298 hasContentType = true; | 190 hasContentType = true; |
299 } | 191 } |
300 if (!nativeAddRequestHeader(mUrlRequestAdapter, header.first
, header.second)) { | 192 if (!nativeAddRequestHeader( |
| 193 mUrlRequestAdapter, header.getKey(), header.getV
alue())) { |
301 destroyRequestAdapter(); | 194 destroyRequestAdapter(); |
302 throw new IllegalArgumentException( | 195 throw new IllegalArgumentException( |
303 "Invalid header " + header.first + "=" + header.
second); | 196 "Invalid header " + header.getKey() + "=" + head
er.getValue()); |
304 } | 197 } |
305 } | 198 } |
306 if (mUploadDataStream != null) { | 199 if (mUploadDataStream != null) { |
307 if (!hasContentType) { | 200 if (!hasContentType) { |
308 throw new IllegalArgumentException( | 201 throw new IllegalArgumentException( |
309 "Requests with upload data must have a Content-T
ype."); | 202 "Requests with upload data must have a Content-T
ype."); |
310 } | 203 } |
311 mUploadDataStream.attachToRequest(this, mUrlRequestAdapter); | 204 mUploadDataStream.attachToRequest(this, mUrlRequestAdapter); |
312 } | 205 } |
313 } catch (RuntimeException e) { | 206 } catch (RuntimeException e) { |
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
474 return RequestPriority.LOW; | 367 return RequestPriority.LOW; |
475 case Builder.REQUEST_PRIORITY_MEDIUM: | 368 case Builder.REQUEST_PRIORITY_MEDIUM: |
476 return RequestPriority.MEDIUM; | 369 return RequestPriority.MEDIUM; |
477 case Builder.REQUEST_PRIORITY_HIGHEST: | 370 case Builder.REQUEST_PRIORITY_HIGHEST: |
478 return RequestPriority.HIGHEST; | 371 return RequestPriority.HIGHEST; |
479 default: | 372 default: |
480 return RequestPriority.MEDIUM; | 373 return RequestPriority.MEDIUM; |
481 } | 374 } |
482 } | 375 } |
483 | 376 |
484 private NativeResponseInfo prepareResponseInfoOnNetworkThread( | 377 private UrlResponseInfo prepareResponseInfoOnNetworkThread(int httpStatusCod
e) { |
485 int httpStatusCode) { | |
486 long urlRequestAdapter; | 378 long urlRequestAdapter; |
487 synchronized (mUrlRequestAdapterLock) { | 379 synchronized (mUrlRequestAdapterLock) { |
488 if (mUrlRequestAdapter == 0) { | 380 if (mUrlRequestAdapter == 0) { |
489 return null; | 381 return null; |
490 } | 382 } |
491 // This method is running on network thread, so even if | 383 // This method is running on network thread, so even if |
492 // mUrlRequestAdapter is set to 0 from another thread the actual | 384 // mUrlRequestAdapter is set to 0 from another thread the actual |
493 // deletion of the adapter is posted to network thread, so it is | 385 // deletion of the adapter is posted to network thread, so it is |
494 // safe to preserve and use urlRequestAdapter outside the lock. | 386 // safe to preserve and use urlRequestAdapter outside the lock. |
495 urlRequestAdapter = mUrlRequestAdapter; | 387 urlRequestAdapter = mUrlRequestAdapter; |
496 } | 388 } |
497 NativeResponseInfo responseInfo = new NativeResponseInfo( | 389 HeadersList headersList = new HeadersList(); |
498 mUrlChain.toArray(new String[mUrlChain.size()]), | 390 nativePopulateResponseHeaders(urlRequestAdapter, headersList); |
499 httpStatusCode, | 391 |
500 nativeGetHttpStatusText(urlRequestAdapter), | 392 UrlResponseInfo responseInfo = new UrlResponseInfo(new ArrayList<String>
(mUrlChain), |
| 393 httpStatusCode, nativeGetHttpStatusText(urlRequestAdapter), head
ersList, |
501 nativeGetWasCached(urlRequestAdapter), | 394 nativeGetWasCached(urlRequestAdapter), |
502 nativeGetNegotiatedProtocol(urlRequestAdapter), | 395 nativeGetNegotiatedProtocol(urlRequestAdapter), |
503 nativeGetProxyServer(urlRequestAdapter)); | 396 nativeGetProxyServer(urlRequestAdapter)); |
504 nativePopulateResponseHeaders(urlRequestAdapter, | |
505 responseInfo.mAllHeaders); | |
506 return responseInfo; | 397 return responseInfo; |
507 } | 398 } |
508 | 399 |
509 private void checkNotStarted() { | 400 private void checkNotStarted() { |
510 synchronized (mUrlRequestAdapterLock) { | 401 synchronized (mUrlRequestAdapterLock) { |
511 if (mStarted || isDone()) { | 402 if (mStarted || isDone()) { |
512 throw new IllegalStateException("Request is already started."); | 403 throw new IllegalStateException("Request is already started."); |
513 } | 404 } |
514 } | 405 } |
515 } | 406 } |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
594 //////////////////////////////////////////////// | 485 //////////////////////////////////////////////// |
595 | 486 |
596 /** | 487 /** |
597 * Called before following redirects. The redirect will automatically be | 488 * Called before following redirects. The redirect will automatically be |
598 * followed, unless the request is paused or canceled during this | 489 * followed, unless the request is paused or canceled during this |
599 * callback. If the redirect response has a body, it will be ignored. | 490 * callback. If the redirect response has a body, it will be ignored. |
600 * This will only be called between start and onResponseStarted. | 491 * This will only be called between start and onResponseStarted. |
601 * | 492 * |
602 * @param newLocation Location where request is redirected. | 493 * @param newLocation Location where request is redirected. |
603 * @param httpStatusCode from redirect response | 494 * @param httpStatusCode from redirect response |
| 495 * @param receivedBytesCount count of bytes received for redirect response |
604 */ | 496 */ |
605 @SuppressWarnings("unused") | 497 @SuppressWarnings("unused") |
606 @CalledByNative | 498 @CalledByNative |
607 private void onReceivedRedirect(final String newLocation, | 499 private void onReceivedRedirect( |
608 int httpStatusCode) { | 500 final String newLocation, int httpStatusCode, long receivedBytesCoun
t) { |
609 final NativeResponseInfo responseInfo = | 501 final UrlResponseInfo responseInfo = prepareResponseInfoOnNetworkThread(
httpStatusCode); |
610 prepareResponseInfoOnNetworkThread(httpStatusCode); | 502 mReceivedBytesCountFromRedirects += receivedBytesCount; |
| 503 responseInfo.setReceivedBytesCount(mReceivedBytesCountFromRedirects); |
611 // Have to do this after creating responseInfo. | 504 // Have to do this after creating responseInfo. |
612 mUrlChain.add(newLocation); | 505 mUrlChain.add(newLocation); |
613 | 506 |
614 Runnable task = new Runnable() { | 507 Runnable task = new Runnable() { |
615 public void run() { | 508 public void run() { |
616 synchronized (mUrlRequestAdapterLock) { | 509 synchronized (mUrlRequestAdapterLock) { |
617 if (isDone()) { | 510 if (isDone()) { |
618 return; | 511 return; |
619 } | 512 } |
620 mWaitingOnRedirect = true; | 513 mWaitingOnRedirect = true; |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
665 * pauses the request, it remains valid until the request is resumed. | 558 * pauses the request, it remains valid until the request is resumed. |
666 * Cancelling the request also invalidates the buffer. | 559 * Cancelling the request also invalidates the buffer. |
667 * | 560 * |
668 * @param byteBuffer ByteBuffer containing received data, starting at | 561 * @param byteBuffer ByteBuffer containing received data, starting at |
669 * initialPosition. Guaranteed to have at least one read byte. Its | 562 * initialPosition. Guaranteed to have at least one read byte. Its |
670 * limit has not yet been updated to reflect the bytes read. | 563 * limit has not yet been updated to reflect the bytes read. |
671 * @param bytesRead Number of bytes read. | 564 * @param bytesRead Number of bytes read. |
672 * @param initialPosition Original position of byteBuffer when passed to | 565 * @param initialPosition Original position of byteBuffer when passed to |
673 * read(). Used as a minimal check that the buffer hasn't been | 566 * read(). Used as a minimal check that the buffer hasn't been |
674 * modified while reading from the network. | 567 * modified while reading from the network. |
| 568 * @param receivedBytesCount number of bytes received. |
675 */ | 569 */ |
676 @SuppressWarnings("unused") | 570 @SuppressWarnings("unused") |
677 @CalledByNative | 571 @CalledByNative |
678 private void onReadCompleted(final ByteBuffer byteBuffer, int bytesRead, | 572 private void onReadCompleted(final ByteBuffer byteBuffer, int bytesRead, int
initialPosition, |
679 int initialPosition) { | 573 long receivedBytesCount) { |
| 574 mResponseInfo.setReceivedBytesCount(mReceivedBytesCountFromRedirects + r
eceivedBytesCount); |
680 if (byteBuffer.position() != initialPosition) { | 575 if (byteBuffer.position() != initialPosition) { |
681 failWithException(new UrlRequestException( | 576 failWithException(new UrlRequestException( |
682 "ByteBuffer modified externally during read", null)); | 577 "ByteBuffer modified externally during read", null)); |
683 return; | 578 return; |
684 } | 579 } |
685 if (mOnReadCompletedTask == null) { | 580 if (mOnReadCompletedTask == null) { |
686 mOnReadCompletedTask = new OnReadCompletedRunnable(); | 581 mOnReadCompletedTask = new OnReadCompletedRunnable(); |
687 } | 582 } |
688 if (mLegacyReadByteBufferAdjustment) { | 583 if (mLegacyReadByteBufferAdjustment) { |
689 byteBuffer.limit(initialPosition + bytesRead); | 584 byteBuffer.limit(initialPosition + bytesRead); |
690 } else { | 585 } else { |
691 byteBuffer.position(initialPosition + bytesRead); | 586 byteBuffer.position(initialPosition + bytesRead); |
692 } | 587 } |
693 mOnReadCompletedTask.mByteBuffer = byteBuffer; | 588 mOnReadCompletedTask.mByteBuffer = byteBuffer; |
694 postTaskToExecutor(mOnReadCompletedTask); | 589 postTaskToExecutor(mOnReadCompletedTask); |
695 } | 590 } |
696 | 591 |
697 /** | 592 /** |
698 * Called when request is completed successfully, no callbacks will be | 593 * Called when request is completed successfully, no callbacks will be |
699 * called afterwards. | 594 * called afterwards. |
| 595 * |
| 596 * @param receivedBytesCount number of bytes received. |
700 */ | 597 */ |
701 @SuppressWarnings("unused") | 598 @SuppressWarnings("unused") |
702 @CalledByNative | 599 @CalledByNative |
703 private void onSucceeded(long totalReceivedBytes) { | 600 private void onSucceeded(long receivedBytesCount) { |
704 final NativeExtendedResponseInfo extendedResponseInfo = | 601 mResponseInfo.setReceivedBytesCount(mReceivedBytesCountFromRedirects + r
eceivedBytesCount); |
705 new NativeExtendedResponseInfo(mResponseInfo, | |
706 totalReceivedBytes); | |
707 Runnable task = new Runnable() { | 602 Runnable task = new Runnable() { |
708 public void run() { | 603 public void run() { |
709 synchronized (mUrlRequestAdapterLock) { | 604 synchronized (mUrlRequestAdapterLock) { |
710 if (isDone()) { | 605 if (isDone()) { |
711 return; | 606 return; |
712 } | 607 } |
713 // Destroy adapter first, so request context could be shut | 608 // Destroy adapter first, so request context could be shut |
714 // down from the listener. | 609 // down from the listener. |
715 destroyRequestAdapter(); | 610 destroyRequestAdapter(); |
716 } | 611 } |
717 try { | 612 try { |
718 mListener.onSucceeded(CronetUrlRequest.this, | 613 mListener.onSucceeded(CronetUrlRequest.this, mResponseInfo); |
719 extendedResponseInfo); | |
720 } catch (Exception e) { | 614 } catch (Exception e) { |
721 Log.e(CronetUrlRequestContext.LOG_TAG, | 615 Log.e(CronetUrlRequestContext.LOG_TAG, |
722 "Exception in onComplete method", e); | 616 "Exception in onComplete method", e); |
723 } | 617 } |
724 } | 618 } |
725 }; | 619 }; |
726 postTaskToExecutor(task); | 620 postTaskToExecutor(task); |
727 } | 621 } |
728 | 622 |
729 /** | 623 /** |
730 * Called when error has occured, no callbacks will be called afterwards. | 624 * Called when error has occured, no callbacks will be called afterwards. |
731 * | 625 * |
732 * @param nativeError native net error code. | 626 * @param nativeError native net error code. |
733 * @param errorString textual representation of the error code. | 627 * @param errorString textual representation of the error code. |
| 628 * @param receivedBytesCount number of bytes received. |
734 */ | 629 */ |
735 @SuppressWarnings("unused") | 630 @SuppressWarnings("unused") |
736 @CalledByNative | 631 @CalledByNative |
737 private void onError(final int nativeError, final String errorString) { | 632 private void onError(final int nativeError, final String errorString, long r
eceivedBytesCount) { |
| 633 if (mResponseInfo != null) { |
| 634 mResponseInfo.setReceivedBytesCount( |
| 635 mReceivedBytesCountFromRedirects + receivedBytesCount); |
| 636 } |
738 UrlRequestException requestError = new UrlRequestException( | 637 UrlRequestException requestError = new UrlRequestException( |
739 "Exception in CronetUrlRequest: " + errorString, | 638 "Exception in CronetUrlRequest: " + errorString, |
740 nativeError); | 639 nativeError); |
741 failWithException(requestError); | 640 failWithException(requestError); |
742 } | 641 } |
743 | 642 |
744 /** | 643 /** |
745 * Appends header |name| with value |value| to |headersList|. | 644 * Appends header |name| with value |value| to |headersList|. |
746 */ | 645 */ |
747 @SuppressWarnings("unused") | 646 @SuppressWarnings("unused") |
748 @CalledByNative | 647 @CalledByNative |
749 private void onAppendResponseHeader(HeadersList headersList, | 648 private void onAppendResponseHeader(HeadersList headersList, |
750 String name, String value) { | 649 String name, String value) { |
751 headersList.add(Pair.create(name, value)); | 650 headersList.add(new AbstractMap.SimpleImmutableEntry<String, String>(nam
e, value)); |
752 } | 651 } |
753 | 652 |
754 /** | 653 /** |
755 * Called by the native code when request status is fetched from the | 654 * Called by the native code when request status is fetched from the |
756 * native stack. | 655 * native stack. |
757 */ | 656 */ |
758 @SuppressWarnings("unused") | 657 @SuppressWarnings("unused") |
759 @CalledByNative | 658 @CalledByNative |
760 private void onStatus(final UrlRequest.StatusListener listener, final int lo
adState) { | 659 private void onStatus(final UrlRequest.StatusListener listener, final int lo
adState) { |
761 Runnable task = new Runnable() { | 660 Runnable task = new Runnable() { |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
805 | 704 |
806 @NativeClassQualifiedName("CronetURLRequestAdapter") | 705 @NativeClassQualifiedName("CronetURLRequestAdapter") |
807 private native String nativeGetProxyServer(long nativePtr); | 706 private native String nativeGetProxyServer(long nativePtr); |
808 | 707 |
809 @NativeClassQualifiedName("CronetURLRequestAdapter") | 708 @NativeClassQualifiedName("CronetURLRequestAdapter") |
810 private native void nativeGetStatus(long nativePtr, UrlRequest.StatusListene
r listener); | 709 private native void nativeGetStatus(long nativePtr, UrlRequest.StatusListene
r listener); |
811 | 710 |
812 @NativeClassQualifiedName("CronetURLRequestAdapter") | 711 @NativeClassQualifiedName("CronetURLRequestAdapter") |
813 private native boolean nativeGetWasCached(long nativePtr); | 712 private native boolean nativeGetWasCached(long nativePtr); |
814 } | 713 } |
OLD | NEW |