| 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.impl; |
| 6 | 6 |
| 7 import android.os.SystemClock; | 7 import android.os.SystemClock; |
| 8 import android.support.annotation.Nullable; | 8 import android.support.annotation.Nullable; |
| 9 import android.util.Log; | 9 import android.util.Log; |
| 10 | 10 |
| 11 import org.chromium.base.VisibleForTesting; | 11 import org.chromium.base.VisibleForTesting; |
| 12 import org.chromium.base.annotations.CalledByNative; | 12 import org.chromium.base.annotations.CalledByNative; |
| 13 import org.chromium.base.annotations.JNIAdditionalImport; | 13 import org.chromium.base.annotations.JNIAdditionalImport; |
| 14 import org.chromium.base.annotations.JNINamespace; | 14 import org.chromium.base.annotations.JNINamespace; |
| 15 import org.chromium.base.annotations.NativeClassQualifiedName; | 15 import org.chromium.base.annotations.NativeClassQualifiedName; |
| 16 import org.chromium.net.CronetEngine.UrlRequestInfo; | 16 import org.chromium.net.CronetEngine.UrlRequestInfo; |
| 17 import org.chromium.net.CronetEngine.UrlRequestMetrics; | 17 import org.chromium.net.CronetEngine.UrlRequestMetrics; |
| 18 import org.chromium.net.Preconditions; |
| 19 import org.chromium.net.QuicException; |
| 20 import org.chromium.net.RequestPriority; |
| 21 import org.chromium.net.UploadDataProvider; |
| 22 import org.chromium.net.UrlRequest; |
| 23 import org.chromium.net.UrlRequestException; |
| 24 import org.chromium.net.UrlResponseInfo; |
| 18 | 25 |
| 19 import java.nio.ByteBuffer; | 26 import java.nio.ByteBuffer; |
| 20 import java.util.AbstractMap; | 27 import java.util.AbstractMap; |
| 21 import java.util.ArrayList; | 28 import java.util.ArrayList; |
| 22 import java.util.Collection; | 29 import java.util.Collection; |
| 23 import java.util.List; | 30 import java.util.List; |
| 24 import java.util.Map; | 31 import java.util.Map; |
| 25 import java.util.concurrent.Executor; | 32 import java.util.concurrent.Executor; |
| 26 import java.util.concurrent.RejectedExecutionException; | 33 import java.util.concurrent.RejectedExecutionException; |
| 27 | 34 |
| 28 import javax.annotation.concurrent.GuardedBy; | 35 import javax.annotation.concurrent.GuardedBy; |
| 29 | 36 |
| 30 /** | 37 /** |
| 31 * UrlRequest using Chromium HTTP stack implementation. Could be accessed from | 38 * UrlRequest using Chromium HTTP stack implementation. Could be accessed from |
| 32 * any thread on Executor. Cancel can be called from any thread. | 39 * any thread on Executor. Cancel can be called from any thread. |
| 33 * All @CallByNative methods are called on native network thread | 40 * All @CallByNative methods are called on native network thread |
| 34 * and post tasks with listener calls onto Executor. Upon return from listener | 41 * and post tasks with listener calls onto Executor. Upon return from listener |
| 35 * callback native request adapter is called on executive thread and posts | 42 * callback native request adapter is called on executive thread and posts |
| 36 * native tasks to native network thread. Because Cancel could be called from | 43 * native tasks to native network thread. Because Cancel could be called from |
| 37 * any thread it is protected by mUrlRequestAdapterLock. | 44 * any thread it is protected by mUrlRequestAdapterLock. |
| 38 */ | 45 */ |
| 39 @JNINamespace("cronet") | 46 @JNINamespace("cronet") |
| 40 // Qualifies UrlRequest.StatusListener which is used in onStatus, a JNI method. | 47 // Qualifies UrlRequest.StatusListener which is used in onStatus, a JNI method. |
| 41 @JNIAdditionalImport(UrlRequest.class) | 48 @JNIAdditionalImport(UrlRequest.class) |
| 42 final class CronetUrlRequest implements UrlRequest { | 49 @VisibleForTesting |
| 50 public final class CronetUrlRequest implements UrlRequest { |
| 43 private static final UrlRequestMetrics EMPTY_METRICS = | 51 private static final UrlRequestMetrics EMPTY_METRICS = |
| 44 new UrlRequestMetrics(null, null, null, null); | 52 new UrlRequestMetrics(null, null, null, null); |
| 45 | 53 |
| 46 /* Native adapter object, owned by UrlRequest. */ | 54 /* Native adapter object, owned by UrlRequest. */ |
| 47 @GuardedBy("mUrlRequestAdapterLock") | 55 @GuardedBy("mUrlRequestAdapterLock") |
| 48 private long mUrlRequestAdapter; | 56 private long mUrlRequestAdapter; |
| 49 | 57 |
| 50 @GuardedBy("mUrlRequestAdapterLock") | 58 @GuardedBy("mUrlRequestAdapterLock") |
| 51 private boolean mStarted = false; | 59 private boolean mStarted = false; |
| 52 @GuardedBy("mUrlRequestAdapterLock") | 60 @GuardedBy("mUrlRequestAdapterLock") |
| (...skipping 278 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 331 }; | 339 }; |
| 332 postTaskToExecutor(task); | 340 postTaskToExecutor(task); |
| 333 } | 341 } |
| 334 | 342 |
| 335 @VisibleForTesting | 343 @VisibleForTesting |
| 336 public void setOnDestroyedCallbackForTesting(Runnable onDestroyedCallbackFor
Testing) { | 344 public void setOnDestroyedCallbackForTesting(Runnable onDestroyedCallbackFor
Testing) { |
| 337 mOnDestroyedCallbackForTesting = onDestroyedCallbackForTesting; | 345 mOnDestroyedCallbackForTesting = onDestroyedCallbackForTesting; |
| 338 } | 346 } |
| 339 | 347 |
| 340 @VisibleForTesting | 348 @VisibleForTesting |
| 341 void setOnDestroyedUploadCallbackForTesting(Runnable onDestroyedUploadCallba
ckForTesting) { | 349 public void setOnDestroyedUploadCallbackForTesting( |
| 350 Runnable onDestroyedUploadCallbackForTesting) { |
| 342 mUploadDataStream.setOnDestroyedCallbackForTesting(onDestroyedUploadCall
backForTesting); | 351 mUploadDataStream.setOnDestroyedCallbackForTesting(onDestroyedUploadCall
backForTesting); |
| 343 } | 352 } |
| 344 | 353 |
| 345 @VisibleForTesting | 354 @VisibleForTesting |
| 346 long getUrlRequestAdapterForTesting() { | 355 public long getUrlRequestAdapterForTesting() { |
| 347 synchronized (mUrlRequestAdapterLock) { | 356 synchronized (mUrlRequestAdapterLock) { |
| 348 return mUrlRequestAdapter; | 357 return mUrlRequestAdapter; |
| 349 } | 358 } |
| 350 } | 359 } |
| 351 | 360 |
| 352 /** | 361 /** |
| 353 * Posts task to application Executor. Used for Listener callbacks | 362 * Posts task to application Executor. Used for Listener callbacks |
| 354 * and other tasks that should not be executed on network thread. | 363 * and other tasks that should not be executed on network thread. |
| 355 */ | 364 */ |
| 356 private void postTaskToExecutor(Runnable task) { | 365 private void postTaskToExecutor(Runnable task) { |
| 357 try { | 366 try { |
| 358 mExecutor.execute(task); | 367 mExecutor.execute(task); |
| 359 } catch (RejectedExecutionException failException) { | 368 } catch (RejectedExecutionException failException) { |
| 360 Log.e(CronetUrlRequestContext.LOG_TAG, | 369 Log.e(CronetUrlRequestContext.LOG_TAG, "Exception posting task to ex
ecutor", |
| 361 "Exception posting task to executor", failException); | 370 failException); |
| 362 // If posting a task throws an exception, then there is no choice | 371 // If posting a task throws an exception, then there is no choice |
| 363 // but to destroy the request without invoking the callback. | 372 // but to destroy the request without invoking the callback. |
| 364 destroyRequestAdapter(false); | 373 destroyRequestAdapter(false); |
| 365 } | 374 } |
| 366 } | 375 } |
| 367 | 376 |
| 368 private static int convertRequestPriority(int priority) { | 377 private static int convertRequestPriority(int priority) { |
| 369 switch (priority) { | 378 switch (priority) { |
| 370 case Builder.REQUEST_PRIORITY_IDLE: | 379 case Builder.REQUEST_PRIORITY_IDLE: |
| 371 return RequestPriority.IDLE; | 380 return RequestPriority.IDLE; |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 421 } | 430 } |
| 422 | 431 |
| 423 /** | 432 /** |
| 424 * If callback method throws an exception, request gets canceled | 433 * If callback method throws an exception, request gets canceled |
| 425 * and exception is reported via onFailed listener callback. | 434 * and exception is reported via onFailed listener callback. |
| 426 * Only called on the Executor. | 435 * Only called on the Executor. |
| 427 */ | 436 */ |
| 428 private void onCallbackException(Exception e) { | 437 private void onCallbackException(Exception e) { |
| 429 UrlRequestException requestError = | 438 UrlRequestException requestError = |
| 430 new UrlRequestException("Exception received from UrlRequest.Call
back", e); | 439 new UrlRequestException("Exception received from UrlRequest.Call
back", e); |
| 431 Log.e(CronetUrlRequestContext.LOG_TAG, | 440 Log.e(CronetUrlRequestContext.LOG_TAG, "Exception in CalledByNative meth
od", e); |
| 432 "Exception in CalledByNative method", e); | |
| 433 // Do not call into listener if request is finished. | 441 // Do not call into listener if request is finished. |
| 434 synchronized (mUrlRequestAdapterLock) { | 442 synchronized (mUrlRequestAdapterLock) { |
| 435 if (isDoneLocked()) { | 443 if (isDoneLocked()) { |
| 436 return; | 444 return; |
| 437 } | 445 } |
| 438 destroyRequestAdapter(false); | 446 destroyRequestAdapter(false); |
| 439 } | 447 } |
| 440 try { | 448 try { |
| 441 mCallback.onFailed(this, mResponseInfo, requestError); | 449 mCallback.onFailed(this, mResponseInfo, requestError); |
| 442 } catch (Exception failException) { | 450 } catch (Exception failException) { |
| 443 Log.e(CronetUrlRequestContext.LOG_TAG, | 451 Log.e(CronetUrlRequestContext.LOG_TAG, "Exception notifying of faile
d request", |
| 444 "Exception notifying of failed request", failException); | 452 failException); |
| 445 } | 453 } |
| 446 } | 454 } |
| 447 | 455 |
| 448 /** | 456 /** |
| 449 * Called when UploadDataProvider encounters an error. | 457 * Called when UploadDataProvider encounters an error. |
| 450 */ | 458 */ |
| 451 void onUploadException(Throwable e) { | 459 void onUploadException(Throwable e) { |
| 452 UrlRequestException uploadError = | 460 UrlRequestException uploadError = |
| 453 new UrlRequestException("Exception received from UploadDataProvi
der", e); | 461 new UrlRequestException("Exception received from UploadDataProvi
der", e); |
| 454 Log.e(CronetUrlRequestContext.LOG_TAG, "Exception in upload method", e); | 462 Log.e(CronetUrlRequestContext.LOG_TAG, "Exception in upload method", e); |
| 455 failWithException(uploadError); | 463 failWithException(uploadError); |
| 456 } | 464 } |
| 457 | 465 |
| 458 /** | 466 /** |
| 459 * Fails the request with an exception. Can be called on any thread. | 467 * Fails the request with an exception. Can be called on any thread. |
| 460 */ | 468 */ |
| 461 private void failWithException(final UrlRequestException exception) { | 469 private void failWithException(final UrlRequestException exception) { |
| 462 Runnable task = new Runnable() { | 470 Runnable task = new Runnable() { |
| 463 @Override | 471 @Override |
| 464 public void run() { | 472 public void run() { |
| 465 synchronized (mUrlRequestAdapterLock) { | 473 synchronized (mUrlRequestAdapterLock) { |
| 466 if (isDoneLocked()) { | 474 if (isDoneLocked()) { |
| 467 return; | 475 return; |
| 468 } | 476 } |
| 469 destroyRequestAdapter(false); | 477 destroyRequestAdapter(false); |
| 470 } | 478 } |
| 471 try { | 479 try { |
| 472 mCallback.onFailed(CronetUrlRequest.this, mResponseInfo, exc
eption); | 480 mCallback.onFailed(CronetUrlRequest.this, mResponseInfo, exc
eption); |
| 473 } catch (Exception e) { | 481 } catch (Exception e) { |
| 474 Log.e(CronetUrlRequestContext.LOG_TAG, | 482 Log.e(CronetUrlRequestContext.LOG_TAG, "Exception in onError
method", e); |
| 475 "Exception in onError method", e); | |
| 476 } | 483 } |
| 477 } | 484 } |
| 478 }; | 485 }; |
| 479 postTaskToExecutor(task); | 486 postTaskToExecutor(task); |
| 480 } | 487 } |
| 481 | 488 |
| 482 //////////////////////////////////////////////// | 489 //////////////////////////////////////////////// |
| 483 // Private methods called by the native code. | 490 // Private methods called by the native code. |
| 484 // Always called on network thread. | 491 // Always called on network thread. |
| 485 //////////////////////////////////////////////// | 492 //////////////////////////////////////////////// |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 579 * read(). Used as a minimal check that the buffer hasn't been | 586 * read(). Used as a minimal check that the buffer hasn't been |
| 580 * modified while reading from the network. | 587 * modified while reading from the network. |
| 581 * @param receivedBytesCount number of bytes received. | 588 * @param receivedBytesCount number of bytes received. |
| 582 */ | 589 */ |
| 583 @SuppressWarnings("unused") | 590 @SuppressWarnings("unused") |
| 584 @CalledByNative | 591 @CalledByNative |
| 585 private void onReadCompleted(final ByteBuffer byteBuffer, int bytesRead, int
initialPosition, | 592 private void onReadCompleted(final ByteBuffer byteBuffer, int bytesRead, int
initialPosition, |
| 586 int initialLimit, long receivedBytesCount) { | 593 int initialLimit, long receivedBytesCount) { |
| 587 mResponseInfo.setReceivedBytesCount(mReceivedBytesCountFromRedirects + r
eceivedBytesCount); | 594 mResponseInfo.setReceivedBytesCount(mReceivedBytesCountFromRedirects + r
eceivedBytesCount); |
| 588 if (byteBuffer.position() != initialPosition || byteBuffer.limit() != in
itialLimit) { | 595 if (byteBuffer.position() != initialPosition || byteBuffer.limit() != in
itialLimit) { |
| 589 failWithException(new UrlRequestException( | 596 failWithException( |
| 590 "ByteBuffer modified externally during read", null)); | 597 new UrlRequestException("ByteBuffer modified externally duri
ng read", null)); |
| 591 return; | 598 return; |
| 592 } | 599 } |
| 593 if (mOnReadCompletedTask == null) { | 600 if (mOnReadCompletedTask == null) { |
| 594 mOnReadCompletedTask = new OnReadCompletedRunnable(); | 601 mOnReadCompletedTask = new OnReadCompletedRunnable(); |
| 595 } | 602 } |
| 596 byteBuffer.position(initialPosition + bytesRead); | 603 byteBuffer.position(initialPosition + bytesRead); |
| 597 mOnReadCompletedTask.mByteBuffer = byteBuffer; | 604 mOnReadCompletedTask.mByteBuffer = byteBuffer; |
| 598 postTaskToExecutor(mOnReadCompletedTask); | 605 postTaskToExecutor(mOnReadCompletedTask); |
| 599 } | 606 } |
| 600 | 607 |
| (...skipping 14 matching lines...) Expand all Loading... |
| 615 if (isDoneLocked()) { | 622 if (isDoneLocked()) { |
| 616 return; | 623 return; |
| 617 } | 624 } |
| 618 // Destroy adapter first, so request context could be shut | 625 // Destroy adapter first, so request context could be shut |
| 619 // down from the listener. | 626 // down from the listener. |
| 620 destroyRequestAdapter(false); | 627 destroyRequestAdapter(false); |
| 621 } | 628 } |
| 622 try { | 629 try { |
| 623 mCallback.onSucceeded(CronetUrlRequest.this, mResponseInfo); | 630 mCallback.onSucceeded(CronetUrlRequest.this, mResponseInfo); |
| 624 } catch (Exception e) { | 631 } catch (Exception e) { |
| 625 Log.e(CronetUrlRequestContext.LOG_TAG, | 632 Log.e(CronetUrlRequestContext.LOG_TAG, "Exception in onCompl
ete method", e); |
| 626 "Exception in onComplete method", e); | |
| 627 } | 633 } |
| 628 } | 634 } |
| 629 }; | 635 }; |
| 630 postTaskToExecutor(task); | 636 postTaskToExecutor(task); |
| 631 } | 637 } |
| 632 | 638 |
| 633 /** | 639 /** |
| 634 * Called when error has occured, no callbacks will be called afterwards. | 640 * Called when error has occured, no callbacks will be called afterwards. |
| 635 * | 641 * |
| 636 * @param errorCode error code from {@link UrlRequestException.ERROR_LISTENE
R_EXCEPTION_THROWN | 642 * @param errorCode error code from {@link UrlRequestException.ERROR_LISTENE
R_EXCEPTION_THROWN |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 692 } | 698 } |
| 693 | 699 |
| 694 UrlRequestInfo getRequestInfo() { | 700 UrlRequestInfo getRequestInfo() { |
| 695 return new UrlRequestInfo(mInitialUrl, mRequestAnnotations, | 701 return new UrlRequestInfo(mInitialUrl, mRequestAnnotations, |
| 696 (mRequestMetricsAccumulator != null ? mRequestMetricsAccumulator
.getRequestMetrics() | 702 (mRequestMetricsAccumulator != null ? mRequestMetricsAccumulator
.getRequestMetrics() |
| 697 : EMPTY_METRICS), | 703 : EMPTY_METRICS), |
| 698 mResponseInfo); | 704 mResponseInfo); |
| 699 } | 705 } |
| 700 | 706 |
| 701 private final class UrlRequestMetricsAccumulator { | 707 private final class UrlRequestMetricsAccumulator { |
| 702 @Nullable private Long mRequestStartTime; | 708 @Nullable |
| 703 @Nullable private Long mTtfbMs; | 709 private Long mRequestStartTime; |
| 704 @Nullable private Long mTotalTimeMs; | 710 @Nullable |
| 711 private Long mTtfbMs; |
| 712 @Nullable |
| 713 private Long mTotalTimeMs; |
| 705 | 714 |
| 706 private UrlRequestMetrics getRequestMetrics() { | 715 private UrlRequestMetrics getRequestMetrics() { |
| 707 return new UrlRequestMetrics(mTtfbMs, mTotalTimeMs, | 716 return new UrlRequestMetrics(mTtfbMs, mTotalTimeMs, |
| 708 null, // TODO(klm): Compute sentBytesCount. | 717 null, // TODO(klm): Compute sentBytesCount. |
| 709 (mResponseInfo != null ? mResponseInfo.getReceivedBytesCount
() : 0)); | 718 (mResponseInfo != null ? mResponseInfo.getReceivedBytesCount
() : 0)); |
| 710 } | 719 } |
| 711 | 720 |
| 712 private void onRequestStarted() { | 721 private void onRequestStarted() { |
| 713 if (mRequestStartTime != null) { | 722 if (mRequestStartTime != null) { |
| 714 throw new IllegalStateException("onRequestStarted called repeate
dly"); | 723 throw new IllegalStateException("onRequestStarted called repeate
dly"); |
| (...skipping 25 matching lines...) Expand all Loading... |
| 740 @NativeClassQualifiedName("CronetURLRequestAdapter") | 749 @NativeClassQualifiedName("CronetURLRequestAdapter") |
| 741 private native boolean nativeAddRequestHeader(long nativePtr, String name, S
tring value); | 750 private native boolean nativeAddRequestHeader(long nativePtr, String name, S
tring value); |
| 742 | 751 |
| 743 @NativeClassQualifiedName("CronetURLRequestAdapter") | 752 @NativeClassQualifiedName("CronetURLRequestAdapter") |
| 744 private native void nativeStart(long nativePtr); | 753 private native void nativeStart(long nativePtr); |
| 745 | 754 |
| 746 @NativeClassQualifiedName("CronetURLRequestAdapter") | 755 @NativeClassQualifiedName("CronetURLRequestAdapter") |
| 747 private native void nativeFollowDeferredRedirect(long nativePtr); | 756 private native void nativeFollowDeferredRedirect(long nativePtr); |
| 748 | 757 |
| 749 @NativeClassQualifiedName("CronetURLRequestAdapter") | 758 @NativeClassQualifiedName("CronetURLRequestAdapter") |
| 750 private native boolean nativeReadData(long nativePtr, ByteBuffer byteBuffer, | 759 private native boolean nativeReadData( |
| 751 int position, int capacity); | 760 long nativePtr, ByteBuffer byteBuffer, int position, int capacity); |
| 752 | 761 |
| 753 @NativeClassQualifiedName("CronetURLRequestAdapter") | 762 @NativeClassQualifiedName("CronetURLRequestAdapter") |
| 754 private native void nativeDestroy(long nativePtr, boolean sendOnCanceled); | 763 private native void nativeDestroy(long nativePtr, boolean sendOnCanceled); |
| 755 | 764 |
| 756 @NativeClassQualifiedName("CronetURLRequestAdapter") | 765 @NativeClassQualifiedName("CronetURLRequestAdapter") |
| 757 private native void nativeGetStatus(long nativePtr, UrlRequest.StatusListene
r listener); | 766 private native void nativeGetStatus(long nativePtr, UrlRequest.StatusListene
r listener); |
| 758 } | 767 } |
| OLD | NEW |