OLD | NEW |
---|---|
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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.annotation.TargetApi; | 7 import android.annotation.TargetApi; |
8 import android.net.TrafficStats; | 8 import android.net.TrafficStats; |
9 import android.os.Build; | 9 import android.os.Build; |
10 import android.util.Log; | 10 import android.util.Log; |
(...skipping 272 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
283 this.mUrlConnection = urlConnection; | 283 this.mUrlConnection = urlConnection; |
284 this.mUploadProvider = provider; | 284 this.mUploadProvider = provider; |
285 } | 285 } |
286 | 286 |
287 @Override | 287 @Override |
288 public void onReadSucceeded(final boolean finalChunk) { | 288 public void onReadSucceeded(final boolean finalChunk) { |
289 if (!mSinkState.compareAndSet(SinkState.AWAITING_READ_RESULT, SinkSt ate.UPLOADING)) { | 289 if (!mSinkState.compareAndSet(SinkState.AWAITING_READ_RESULT, SinkSt ate.UPLOADING)) { |
290 throw new IllegalStateException( | 290 throw new IllegalStateException( |
291 "Not expecting a read result, expecting: " + mSinkState. get()); | 291 "Not expecting a read result, expecting: " + mSinkState. get()); |
292 } | 292 } |
293 mExecutor.execute(errorSetting(State.STARTED, new CheckedRunnable() { | 293 mExecutor.execute(errorSetting(new CheckedRunnable() { |
294 @Override | 294 @Override |
295 public void run() throws Exception { | 295 public void run() throws Exception { |
296 mBuffer.flip(); | 296 mBuffer.flip(); |
297 if (mTotalBytes != -1 && mTotalBytes - mWrittenBytes < mBuff er.remaining()) { | 297 if (mTotalBytes != -1 && mTotalBytes - mWrittenBytes < mBuff er.remaining()) { |
298 enterUploadErrorState(new IllegalArgumentException(Strin g.format( | 298 enterUploadErrorState(new IllegalArgumentException(Strin g.format( |
299 "Read upload data length %d exceeds expected len gth %d", | 299 "Read upload data length %d exceeds expected len gth %d", |
300 mWrittenBytes + mBuffer.remaining(), mTotalBytes ))); | 300 mWrittenBytes + mBuffer.remaining(), mTotalBytes ))); |
301 return; | 301 return; |
302 } | 302 } |
303 while (mBuffer.hasRemaining()) { | 303 while (mBuffer.hasRemaining()) { |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
337 public void onReadError(Exception exception) { | 337 public void onReadError(Exception exception) { |
338 enterUploadErrorState(exception); | 338 enterUploadErrorState(exception); |
339 } | 339 } |
340 | 340 |
341 @Override | 341 @Override |
342 public void onRewindError(Exception exception) { | 342 public void onRewindError(Exception exception) { |
343 enterUploadErrorState(exception); | 343 enterUploadErrorState(exception); |
344 } | 344 } |
345 | 345 |
346 void startRead() { | 346 void startRead() { |
347 mExecutor.execute(errorSetting(State.STARTED, new CheckedRunnable() { | 347 mExecutor.execute(errorSetting(new CheckedRunnable() { |
348 @Override | 348 @Override |
349 public void run() throws Exception { | 349 public void run() throws Exception { |
350 if (mOutputChannel == null) { | 350 if (mOutputChannel == null) { |
351 mAdditionalStatusDetails = Status.CONNECTING; | 351 mAdditionalStatusDetails = Status.CONNECTING; |
352 mUrlConnection.connect(); | 352 mUrlConnection.connect(); |
353 mAdditionalStatusDetails = Status.SENDING_REQUEST; | 353 mAdditionalStatusDetails = Status.SENDING_REQUEST; |
354 mOutputChannel = Channels.newChannel(mUrlConnection.getO utputStream()); | 354 mOutputChannel = Channels.newChannel(mUrlConnection.getO utputStream()); |
355 } | 355 } |
356 mSinkState.set(SinkState.AWAITING_READ_RESULT); | 356 mSinkState.set(SinkState.AWAITING_READ_RESULT); |
357 executeOnUploadExecutor(new CheckedRunnable() { | 357 executeOnUploadExecutor(new CheckedRunnable() { |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
425 mAdditionalStatusDetails = Status.CONNECTING; | 425 mAdditionalStatusDetails = Status.CONNECTING; |
426 transitionStates(State.NOT_STARTED, State.STARTED, new Runnable() { | 426 transitionStates(State.NOT_STARTED, State.STARTED, new Runnable() { |
427 @Override | 427 @Override |
428 public void run() { | 428 public void run() { |
429 mUrlChain.add(mCurrentUrl); | 429 mUrlChain.add(mCurrentUrl); |
430 fireOpenConnection(); | 430 fireOpenConnection(); |
431 } | 431 } |
432 }); | 432 }); |
433 } | 433 } |
434 | 434 |
435 private void enterErrorState(State previousState, final UrlRequestException error) { | 435 private void enterErrorState(final UrlRequestException error) { |
436 if (mState.compareAndSet(previousState, State.ERROR)) { | 436 if (setTerminalState(State.ERROR)) { |
437 fireDisconnect(); | 437 fireDisconnect(); |
438 fireCloseUploadDataProvider(); | 438 fireCloseUploadDataProvider(); |
439 mCallbackAsync.onFailed(mUrlResponseInfo, error); | 439 mCallbackAsync.onFailed(mUrlResponseInfo, error); |
440 } | 440 } |
441 } | 441 } |
442 | 442 |
443 private boolean setTerminalState(State error) { | |
444 while (true) { | |
xunjieli
2016/09/02 21:05:01
I don't understand the need for a while-true loop.
Charles
2016/09/02 21:08:36
We're doing a compare-and-set continuously until w
xunjieli
2016/09/02 21:41:14
Acknowledged.
| |
445 State oldState = mState.get(); | |
446 switch (oldState) { | |
447 case NOT_STARTED: | |
448 throw new IllegalStateException("Can't enter error state bef ore start"); | |
449 case ERROR: // fallthrough | |
450 case COMPLETE: // fallthrough | |
451 case CANCELLED: | |
452 return false; // Already in a terminal state | |
453 default: { | |
454 if (mState.compareAndSet(oldState, error)) { | |
455 return true; | |
456 } | |
457 } | |
458 } | |
459 } | |
460 } | |
461 | |
443 /** Ends the request with an error, caused by an exception thrown from user code. */ | 462 /** Ends the request with an error, caused by an exception thrown from user code. */ |
444 private void enterUserErrorState(State previousState, final Throwable error) { | 463 private void enterUserErrorState(final Throwable error) { |
445 enterErrorState(previousState, | 464 enterErrorState( |
446 new UrlRequestException("Exception received from UrlRequest.Call back", error)); | 465 new UrlRequestException("Exception received from UrlRequest.Call back", error)); |
447 } | 466 } |
448 | 467 |
449 /** Ends the request with an error, caused by an exception thrown from user code. */ | 468 /** Ends the request with an error, caused by an exception thrown from user code. */ |
450 private void enterUploadErrorState(final Throwable error) { | 469 private void enterUploadErrorState(final Throwable error) { |
451 enterErrorState(State.STARTED, | 470 enterErrorState( |
452 new UrlRequestException("Exception received from UploadDataProvi der", error)); | 471 new UrlRequestException("Exception received from UploadDataProvi der", error)); |
453 } | 472 } |
454 | 473 |
455 private void enterCronetErrorState(State previousState, final Throwable erro r) { | 474 private void enterCronetErrorState(final Throwable error) { |
456 // TODO(clm) mapping from Java exception (UnknownHostException, for exam ple) to net error | 475 // TODO(clm) mapping from Java exception (UnknownHostException, for exam ple) to net error |
457 // code goes here. | 476 // code goes here. |
458 enterErrorState(previousState, new UrlRequestException("System error", e rror)); | 477 enterErrorState(new UrlRequestException("System error", error)); |
459 } | 478 } |
460 | 479 |
461 /** | 480 /** |
462 * Atomically swaps from the expected state to a new state. If the swap fail s, and it's not | 481 * Atomically swaps from the expected state to a new state. If the swap fail s, and it's not |
463 * due to an earlier error or cancellation, throws an exception. | 482 * due to an earlier error or cancellation, throws an exception. |
464 * | 483 * |
465 * @param afterTransition Callback to run after transition completes success fully. | 484 * @param afterTransition Callback to run after transition completes success fully. |
466 */ | 485 */ |
467 private void transitionStates(State expected, State newState, Runnable after Transition) { | 486 private void transitionStates(State expected, State newState, Runnable after Transition) { |
468 if (!mState.compareAndSet(expected, newState)) { | 487 if (!mState.compareAndSet(expected, newState)) { |
(...skipping 14 matching lines...) Expand all Loading... | |
483 public void run() { | 502 public void run() { |
484 mCurrentUrl = mPendingRedirectUrl; | 503 mCurrentUrl = mPendingRedirectUrl; |
485 mPendingRedirectUrl = null; | 504 mPendingRedirectUrl = null; |
486 fireOpenConnection(); | 505 fireOpenConnection(); |
487 } | 506 } |
488 }); | 507 }); |
489 } | 508 } |
490 | 509 |
491 private void fireGetHeaders() { | 510 private void fireGetHeaders() { |
492 mAdditionalStatusDetails = Status.WAITING_FOR_RESPONSE; | 511 mAdditionalStatusDetails = Status.WAITING_FOR_RESPONSE; |
493 mExecutor.execute(errorSetting(State.STARTED, new CheckedRunnable() { | 512 mExecutor.execute(errorSetting(new CheckedRunnable() { |
494 @Override | 513 @Override |
495 public void run() throws Exception { | 514 public void run() throws Exception { |
496 HttpURLConnection connection = mCurrentUrlConnection.get(); | 515 HttpURLConnection connection = mCurrentUrlConnection.get(); |
497 if (connection == null) { | 516 if (connection == null) { |
498 return; // We've been cancelled | 517 return; // We've been cancelled |
499 } | 518 } |
500 final List<Map.Entry<String, String>> headerList = new ArrayList <>(); | 519 final List<Map.Entry<String, String>> headerList = new ArrayList <>(); |
501 String selectedTransport = "http/1.1"; | 520 String selectedTransport = "http/1.1"; |
502 String headerKey; | 521 String headerKey; |
503 for (int i = 0; (headerKey = connection.getHeaderFieldKey(i)) != null; i++) { | 522 for (int i = 0; (headerKey = connection.getHeaderFieldKey(i)) != null; i++) { |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
562 public void run() { | 581 public void run() { |
563 mCallbackAsync.onRedirectReceived( | 582 mCallbackAsync.onRedirectReceived( |
564 mUrlResponseInfo, mPendingRedirectUrl); | 583 mUrlResponseInfo, mPendingRedirectUrl); |
565 } | 584 } |
566 }); | 585 }); |
567 } | 586 } |
568 }); | 587 }); |
569 } | 588 } |
570 | 589 |
571 private void fireOpenConnection() { | 590 private void fireOpenConnection() { |
572 mExecutor.execute(errorSetting(State.STARTED, new CheckedRunnable() { | 591 mExecutor.execute(errorSetting(new CheckedRunnable() { |
573 @Override | 592 @Override |
574 public void run() throws Exception { | 593 public void run() throws Exception { |
575 // If we're cancelled, then our old connection will be disconnec ted for us and | 594 // If we're cancelled, then our old connection will be disconnec ted for us and |
576 // we shouldn't open a new one. | 595 // we shouldn't open a new one. |
577 if (mState.get() == State.CANCELLED) { | 596 if (mState.get() == State.CANCELLED) { |
578 return; | 597 return; |
579 } | 598 } |
580 | 599 |
581 final URL url = new URL(mCurrentUrl); | 600 final URL url = new URL(mCurrentUrl); |
582 HttpURLConnection newConnection = (HttpURLConnection) url.openCo nnection(); | 601 HttpURLConnection newConnection = (HttpURLConnection) url.openCo nnection(); |
(...skipping 18 matching lines...) Expand all Loading... | |
601 dataSink.start(mUrlChain.size() == 1); | 620 dataSink.start(mUrlChain.size() == 1); |
602 } else { | 621 } else { |
603 mAdditionalStatusDetails = Status.CONNECTING; | 622 mAdditionalStatusDetails = Status.CONNECTING; |
604 newConnection.connect(); | 623 newConnection.connect(); |
605 fireGetHeaders(); | 624 fireGetHeaders(); |
606 } | 625 } |
607 } | 626 } |
608 })); | 627 })); |
609 } | 628 } |
610 | 629 |
611 private Runnable errorSetting(final State expectedState, final CheckedRunnab le delegate) { | 630 private Runnable errorSetting(final CheckedRunnable delegate) { |
612 return new Runnable() { | 631 return new Runnable() { |
613 @Override | 632 @Override |
614 public void run() { | 633 public void run() { |
615 try { | 634 try { |
616 delegate.run(); | 635 delegate.run(); |
617 } catch (Throwable t) { | 636 } catch (Throwable t) { |
618 enterCronetErrorState(expectedState, t); | 637 enterCronetErrorState(t); |
619 } | 638 } |
620 } | 639 } |
621 }; | 640 }; |
622 } | 641 } |
623 | 642 |
624 private Runnable userErrorSetting(final State expectedState, final CheckedRu nnable delegate) { | 643 private Runnable userErrorSetting(final CheckedRunnable delegate) { |
625 return new Runnable() { | 644 return new Runnable() { |
626 @Override | 645 @Override |
627 public void run() { | 646 public void run() { |
628 try { | 647 try { |
629 delegate.run(); | 648 delegate.run(); |
630 } catch (Throwable t) { | 649 } catch (Throwable t) { |
631 enterUserErrorState(expectedState, t); | 650 enterUserErrorState(t); |
632 } | 651 } |
633 } | 652 } |
634 }; | 653 }; |
635 } | 654 } |
636 | 655 |
637 private Runnable uploadErrorSetting(final CheckedRunnable delegate) { | 656 private Runnable uploadErrorSetting(final CheckedRunnable delegate) { |
638 return new Runnable() { | 657 return new Runnable() { |
639 @Override | 658 @Override |
640 public void run() { | 659 public void run() { |
641 try { | 660 try { |
642 delegate.run(); | 661 delegate.run(); |
643 } catch (Throwable t) { | 662 } catch (Throwable t) { |
644 enterUploadErrorState(t); | 663 enterUploadErrorState(t); |
645 } | 664 } |
646 } | 665 } |
647 }; | 666 }; |
648 } | 667 } |
649 | 668 |
650 private interface CheckedRunnable { void run() throws Exception; } | 669 private interface CheckedRunnable { void run() throws Exception; } |
651 | 670 |
652 @Override | 671 @Override |
653 public void read(final ByteBuffer buffer) { | 672 public void read(final ByteBuffer buffer) { |
654 Preconditions.checkDirect(buffer); | 673 Preconditions.checkDirect(buffer); |
655 Preconditions.checkHasRemaining(buffer); | 674 Preconditions.checkHasRemaining(buffer); |
656 transitionStates(State.AWAITING_READ, State.READING, new Runnable() { | 675 transitionStates(State.AWAITING_READ, State.READING, new Runnable() { |
657 @Override | 676 @Override |
658 public void run() { | 677 public void run() { |
659 mExecutor.execute(errorSetting(State.READING, new CheckedRunnabl e() { | 678 mExecutor.execute(errorSetting(new CheckedRunnable() { |
660 @Override | 679 @Override |
661 public void run() throws Exception { | 680 public void run() throws Exception { |
662 int read = mResponseChannel.read(buffer); | 681 int read = mResponseChannel.read(buffer); |
663 processReadResult(read, buffer); | 682 processReadResult(read, buffer); |
664 } | 683 } |
665 })); | 684 })); |
666 } | 685 } |
667 }); | 686 }); |
668 } | 687 } |
669 | 688 |
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
774 | 793 |
775 void sendStatus(final StatusListener listener, final int status) { | 794 void sendStatus(final StatusListener listener, final int status) { |
776 mUserExecutor.execute(new Runnable() { | 795 mUserExecutor.execute(new Runnable() { |
777 @Override | 796 @Override |
778 public void run() { | 797 public void run() { |
779 listener.onStatus(status); | 798 listener.onStatus(status); |
780 } | 799 } |
781 }); | 800 }); |
782 } | 801 } |
783 | 802 |
784 void execute(State currentState, CheckedRunnable runnable) { | 803 void execute(CheckedRunnable runnable) { |
785 try { | 804 try { |
786 mUserExecutor.execute(userErrorSetting(currentState, runnable)); | 805 mUserExecutor.execute(userErrorSetting(runnable)); |
787 } catch (RejectedExecutionException e) { | 806 } catch (RejectedExecutionException e) { |
788 enterErrorState(currentState, | 807 enterErrorState(new UrlRequestException("Exception posting task to executor", e)); |
789 new UrlRequestException("Exception posting task to execu tor", e)); | |
790 } | 808 } |
791 } | 809 } |
792 | 810 |
793 void onRedirectReceived(final UrlResponseInfo info, final String newLoca tionUrl) { | 811 void onRedirectReceived(final UrlResponseInfo info, final String newLoca tionUrl) { |
794 execute(State.AWAITING_FOLLOW_REDIRECT, new CheckedRunnable() { | 812 execute(new CheckedRunnable() { |
795 @Override | 813 @Override |
796 public void run() throws Exception { | 814 public void run() throws Exception { |
797 mCallback.onRedirectReceived(JavaUrlRequest.this, info, newL ocationUrl); | 815 mCallback.onRedirectReceived(JavaUrlRequest.this, info, newL ocationUrl); |
798 } | 816 } |
799 }); | 817 }); |
800 } | 818 } |
801 | 819 |
802 void onResponseStarted(UrlResponseInfo info) { | 820 void onResponseStarted(UrlResponseInfo info) { |
803 if (mState.compareAndSet(State.STARTED, State.AWAITING_READ)) { | 821 execute(new CheckedRunnable() { |
804 execute(State.AWAITING_READ, new CheckedRunnable() { | 822 @Override |
805 @Override | 823 public void run() throws Exception { |
806 public void run() throws Exception { | 824 if (mState.compareAndSet(State.STARTED, State.AWAITING_READ) ) { |
807 mCallback.onResponseStarted(JavaUrlRequest.this, mUrlRes ponseInfo); | 825 mCallback.onResponseStarted(JavaUrlRequest.this, mUrlRes ponseInfo); |
808 } | 826 } |
809 }); | 827 } |
810 } | 828 }); |
811 } | 829 } |
812 | 830 |
813 void onReadCompleted(final UrlResponseInfo info, final ByteBuffer byteBu ffer) { | 831 void onReadCompleted(final UrlResponseInfo info, final ByteBuffer byteBu ffer) { |
814 if (mState.compareAndSet(State.READING, State.AWAITING_READ)) { | 832 execute(new CheckedRunnable() { |
815 execute(State.AWAITING_READ, new CheckedRunnable() { | 833 @Override |
816 @Override | 834 public void run() throws Exception { |
817 public void run() throws Exception { | 835 if (mState.compareAndSet(State.READING, State.AWAITING_READ) ) { |
818 mCallback.onReadCompleted(JavaUrlRequest.this, info, byt eBuffer); | 836 mCallback.onReadCompleted(JavaUrlRequest.this, info, byt eBuffer); |
819 } | 837 } |
820 }); | 838 } |
821 } | 839 }); |
822 } | 840 } |
823 | 841 |
824 void onCanceled(final UrlResponseInfo info) { | 842 void onCanceled(final UrlResponseInfo info) { |
825 closeResponseChannel(); | 843 closeResponseChannel(); |
826 mUserExecutor.execute(new Runnable() { | 844 mUserExecutor.execute(new Runnable() { |
827 @Override | 845 @Override |
828 public void run() { | 846 public void run() { |
829 try { | 847 try { |
830 mCallback.onCanceled(JavaUrlRequest.this, info); | 848 mCallback.onCanceled(JavaUrlRequest.this, info); |
831 } catch (Exception exception) { | 849 } catch (Exception exception) { |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
931 // Can't throw directly from here, since the delegate execut or could catch this | 949 // Can't throw directly from here, since the delegate execut or could catch this |
932 // exception. | 950 // exception. |
933 mExecutedInline = new InlineExecutionProhibitedException(); | 951 mExecutedInline = new InlineExecutionProhibitedException(); |
934 return; | 952 return; |
935 } | 953 } |
936 mCommand.run(); | 954 mCommand.run(); |
937 } | 955 } |
938 } | 956 } |
939 } | 957 } |
940 } | 958 } |
OLD | NEW |