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

Side by Side Diff: net/url_request/url_fetcher_core.cc

Issue 11464028: Introduce ERR_NETWORK_CHANGED and allow URLFetcher to automatically retry on that error. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebased, post first try if online, more tests Created 8 years 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 #include "net/url_request/url_fetcher_core.h" 5 #include "net/url_request/url_fetcher_core.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/file_util_proxy.h" 8 #include "base/file_util_proxy.h"
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/single_thread_task_runner.h" 10 #include "base/single_thread_task_runner.h"
(...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after
273 delegate_(d), 273 delegate_(d),
274 delegate_task_runner_( 274 delegate_task_runner_(
275 base::ThreadTaskRunnerHandle::Get()), 275 base::ThreadTaskRunnerHandle::Get()),
276 request_(NULL), 276 request_(NULL),
277 load_flags_(LOAD_NORMAL), 277 load_flags_(LOAD_NORMAL),
278 response_code_(URLFetcher::RESPONSE_CODE_INVALID), 278 response_code_(URLFetcher::RESPONSE_CODE_INVALID),
279 buffer_(new IOBuffer(kBufferSize)), 279 buffer_(new IOBuffer(kBufferSize)),
280 url_request_data_key_(NULL), 280 url_request_data_key_(NULL),
281 was_fetched_via_proxy_(false), 281 was_fetched_via_proxy_(false),
282 is_chunked_upload_(false), 282 is_chunked_upload_(false),
283 num_retries_(0),
284 was_cancelled_(false), 283 was_cancelled_(false),
285 response_destination_(STRING), 284 response_destination_(STRING),
286 stop_on_redirect_(false), 285 stop_on_redirect_(false),
287 stopped_on_redirect_(false), 286 stopped_on_redirect_(false),
288 automatically_retry_on_5xx_(true), 287 automatically_retry_on_5xx_(true),
289 max_retries_(0), 288 num_retries_on_5xx_(0),
289 max_retries_on_5xx_(0),
290 num_retries_on_network_changes_(0),
291 max_retries_on_network_changes_(0),
290 current_upload_bytes_(-1), 292 current_upload_bytes_(-1),
291 current_response_bytes_(0), 293 current_response_bytes_(0),
292 total_response_bytes_(-1) { 294 total_response_bytes_(-1) {
293 CHECK(original_url_.is_valid()); 295 CHECK(original_url_.is_valid());
294 } 296 }
295 297
296 void URLFetcherCore::Start() { 298 void URLFetcherCore::Start() {
297 DCHECK(delegate_task_runner_); 299 DCHECK(delegate_task_runner_);
298 DCHECK(request_context_getter_) << "We need an URLRequestContext!"; 300 DCHECK(request_context_getter_) << "We need an URLRequestContext!";
299 if (network_task_runner_) { 301 if (network_task_runner_) {
300 DCHECK_EQ(network_task_runner_, 302 DCHECK_EQ(network_task_runner_,
301 request_context_getter_->GetNetworkTaskRunner()); 303 request_context_getter_->GetNetworkTaskRunner());
302 } else { 304 } else {
303 network_task_runner_ = request_context_getter_->GetNetworkTaskRunner(); 305 network_task_runner_ = request_context_getter_->GetNetworkTaskRunner();
304 } 306 }
305 DCHECK(network_task_runner_.get()) << "We need an IO task runner"; 307 DCHECK(network_task_runner_.get()) << "We need an IO task runner";
306 308
307 network_task_runner_->PostTask( 309 if (NetworkChangeNotifier::IsOffline() &&
308 FROM_HERE, base::Bind(&URLFetcherCore::StartOnIOThread, this)); 310 num_retries_on_network_changes_ < max_retries_on_network_changes_) {
311 // We're currently offline and this request will immediately fail. Try to
312 // start later if |max_retries_on_network_changes_| is set, indicating that
313 // our owner wants the fetcher to automatically retry on network changes.
314 num_retries_on_network_changes_++;
315 NetworkChangeNotifier::AddConnectionTypeObserver(this);
316 } else {
317 network_task_runner_->PostTask(
318 FROM_HERE, base::Bind(&URLFetcherCore::StartOnIOThread, this));
319 }
309 } 320 }
310 321
311 void URLFetcherCore::Stop() { 322 void URLFetcherCore::Stop() {
312 if (delegate_task_runner_) // May be NULL in tests. 323 if (delegate_task_runner_) // May be NULL in tests.
313 DCHECK(delegate_task_runner_->BelongsToCurrentThread()); 324 DCHECK(delegate_task_runner_->BelongsToCurrentThread());
314 325
315 delegate_ = NULL; 326 delegate_ = NULL;
316 fetcher_ = NULL; 327 fetcher_ = NULL;
317 if (!network_task_runner_.get()) 328 if (!network_task_runner_.get())
318 return; 329 return;
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
400 } 411 }
401 412
402 void URLFetcherCore::SetStopOnRedirect(bool stop_on_redirect) { 413 void URLFetcherCore::SetStopOnRedirect(bool stop_on_redirect) {
403 stop_on_redirect_ = stop_on_redirect; 414 stop_on_redirect_ = stop_on_redirect;
404 } 415 }
405 416
406 void URLFetcherCore::SetAutomaticallyRetryOn5xx(bool retry) { 417 void URLFetcherCore::SetAutomaticallyRetryOn5xx(bool retry) {
407 automatically_retry_on_5xx_ = retry; 418 automatically_retry_on_5xx_ = retry;
408 } 419 }
409 420
410 void URLFetcherCore::SetMaxRetries(int max_retries) { 421 void URLFetcherCore::SetMaxRetriesOn5xx(int max_retries) {
411 max_retries_ = max_retries; 422 max_retries_on_5xx_ = max_retries;
412 } 423 }
413 424
414 int URLFetcherCore::GetMaxRetries() const { 425 int URLFetcherCore::GetMaxRetriesOn5xx() const {
415 return max_retries_; 426 return max_retries_on_5xx_;
416 } 427 }
417 428
418 base::TimeDelta URLFetcherCore::GetBackoffDelay() const { 429 base::TimeDelta URLFetcherCore::GetBackoffDelay() const {
419 return backoff_delay_; 430 return backoff_delay_;
420 } 431 }
421 432
433 void URLFetcherCore::SetAutomaticallyRetryOnNetworkChanges(int max_retries) {
434 max_retries_on_network_changes_ = max_retries;
435 }
436
422 void URLFetcherCore::SaveResponseToFileAtPath( 437 void URLFetcherCore::SaveResponseToFileAtPath(
423 const FilePath& file_path, 438 const FilePath& file_path,
424 scoped_refptr<base::TaskRunner> file_task_runner) { 439 scoped_refptr<base::TaskRunner> file_task_runner) {
425 DCHECK(delegate_task_runner_->BelongsToCurrentThread()); 440 DCHECK(delegate_task_runner_->BelongsToCurrentThread());
426 file_task_runner_ = file_task_runner; 441 file_task_runner_ = file_task_runner;
427 response_destination_ = URLFetcherCore::PERMANENT_FILE; 442 response_destination_ = URLFetcherCore::PERMANENT_FILE;
428 response_destination_file_path_ = file_path; 443 response_destination_file_path_ = file_path;
429 } 444 }
430 445
431 void URLFetcherCore::SaveResponseToTemporaryFile( 446 void URLFetcherCore::SaveResponseToTemporaryFile(
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after
599 // If the file is open, close it. After closing the file, 614 // If the file is open, close it. After closing the file,
600 // RetryOrCompleteUrlFetch() will be called. 615 // RetryOrCompleteUrlFetch() will be called.
601 file_writer_->CloseFileAndCompleteRequest(); 616 file_writer_->CloseFileAndCompleteRequest();
602 } else { 617 } else {
603 // Otherwise, complete or retry the URL request directly. 618 // Otherwise, complete or retry the URL request directly.
604 RetryOrCompleteUrlFetch(); 619 RetryOrCompleteUrlFetch();
605 } 620 }
606 } 621 }
607 } 622 }
608 623
624 void URLFetcherCore::OnConnectionTypeChanged(
625 NetworkChangeNotifier::ConnectionType type) {
626 DCHECK_GT(num_retries_on_network_changes_, 0);
627 if (type == NetworkChangeNotifier::CONNECTION_NONE) {
628 // Keep waiting.
629 return;
630 }
631
632 // Stop observing and try again now.
633 NetworkChangeNotifier::RemoveConnectionTypeObserver(this);
634 network_task_runner_->PostTask(
635 FROM_HERE, base::Bind(&URLFetcherCore::StartOnIOThread, this));
636 }
637
609 void URLFetcherCore::CancelAll() { 638 void URLFetcherCore::CancelAll() {
610 g_registry.Get().CancelAll(); 639 g_registry.Get().CancelAll();
611 } 640 }
612 641
613 int URLFetcherCore::GetNumFetcherCores() { 642 int URLFetcherCore::GetNumFetcherCores() {
614 return g_registry.Get().size(); 643 return g_registry.Get().size();
615 } 644 }
616 645
617 void URLFetcherCore::SetEnableInterceptionForTests(bool enabled) { 646 void URLFetcherCore::SetEnableInterceptionForTests(bool enabled) {
618 g_interception_enabled = enabled; 647 g_interception_enabled = enabled;
(...skipping 212 matching lines...) Expand 10 before | Expand all | Expand 10 after
831 860
832 void URLFetcherCore::RetryOrCompleteUrlFetch() { 861 void URLFetcherCore::RetryOrCompleteUrlFetch() {
833 DCHECK(network_task_runner_->BelongsToCurrentThread()); 862 DCHECK(network_task_runner_->BelongsToCurrentThread());
834 base::TimeDelta backoff_delay; 863 base::TimeDelta backoff_delay;
835 864
836 // Checks the response from server. 865 // Checks the response from server.
837 if (response_code_ >= 500 || 866 if (response_code_ >= 500 ||
838 status_.error() == ERR_TEMPORARILY_THROTTLED) { 867 status_.error() == ERR_TEMPORARILY_THROTTLED) {
839 // When encountering a server error, we will send the request again 868 // When encountering a server error, we will send the request again
840 // after backoff time. 869 // after backoff time.
841 ++num_retries_; 870 ++num_retries_on_5xx_;
842 871
843 // Note that backoff_delay may be 0 because (a) the 872 // Note that backoff_delay may be 0 because (a) the
844 // URLRequestThrottlerManager and related code does not 873 // URLRequestThrottlerManager and related code does not
845 // necessarily back off on the first error, (b) it only backs off 874 // necessarily back off on the first error, (b) it only backs off
846 // on some of the 5xx status codes, (c) not all URLRequestContexts 875 // on some of the 5xx status codes, (c) not all URLRequestContexts
847 // have a throttler manager. 876 // have a throttler manager.
848 base::TimeTicks backoff_release_time = GetBackoffReleaseTime(); 877 base::TimeTicks backoff_release_time = GetBackoffReleaseTime();
849 backoff_delay = backoff_release_time - base::TimeTicks::Now(); 878 backoff_delay = backoff_release_time - base::TimeTicks::Now();
850 if (backoff_delay < base::TimeDelta()) 879 if (backoff_delay < base::TimeDelta())
851 backoff_delay = base::TimeDelta(); 880 backoff_delay = base::TimeDelta();
852 881
853 if (automatically_retry_on_5xx_ && num_retries_ <= max_retries_) { 882 if (automatically_retry_on_5xx_ &&
883 num_retries_on_5xx_ <= max_retries_on_5xx_) {
854 StartOnIOThread(); 884 StartOnIOThread();
855 return; 885 return;
856 } 886 }
857 } else { 887 } else {
858 backoff_delay = base::TimeDelta(); 888 backoff_delay = base::TimeDelta();
859 } 889 }
890
891 // Retry if the request failed due to network changes.
892 if (status_.error() == ERR_NETWORK_CHANGED &&
893 num_retries_on_network_changes_ < max_retries_on_network_changes_) {
894 num_retries_on_network_changes_++;
szym 2012/12/10 18:36:31 nit: pre-increment
Joao da Silva 2012/12/11 13:36:43 Done.
895
896 if (NetworkChangeNotifier::IsOffline()) {
897 // Retry once we're back online.
898 NetworkChangeNotifier::AddConnectionTypeObserver(this);
899 } else {
900 // Retry soon, after flushing all the current tasks which may include
901 // further network change observers.
902 network_task_runner_->PostTask(
903 FROM_HERE, base::Bind(&URLFetcherCore::StartOnIOThread, this));
904 }
905 return;
906 }
907
860 request_context_getter_ = NULL; 908 request_context_getter_ = NULL;
861 first_party_for_cookies_ = GURL(); 909 first_party_for_cookies_ = GURL();
862 url_request_data_key_ = NULL; 910 url_request_data_key_ = NULL;
863 url_request_create_data_callback_.Reset(); 911 url_request_create_data_callback_.Reset();
864 bool posted = delegate_task_runner_->PostTask( 912 bool posted = delegate_task_runner_->PostTask(
865 FROM_HERE, 913 FROM_HERE,
866 base::Bind(&URLFetcherCore::OnCompletedURLRequest, this, backoff_delay)); 914 base::Bind(&URLFetcherCore::OnCompletedURLRequest, this, backoff_delay));
867 915
868 // If the delegate message loop does not exist any more, then the delegate 916 // If the delegate message loop does not exist any more, then the delegate
869 // should be gone too. 917 // should be gone too.
870 DCHECK(posted || !delegate_); 918 DCHECK(posted || !delegate_);
871 } 919 }
872 920
873 void URLFetcherCore::ReleaseRequest() { 921 void URLFetcherCore::ReleaseRequest() {
922 if (num_retries_on_network_changes_ > 0)
923 NetworkChangeNotifier::RemoveConnectionTypeObserver(this);
874 upload_progress_checker_timer_.reset(); 924 upload_progress_checker_timer_.reset();
875 request_.reset(); 925 request_.reset();
876 g_registry.Get().RemoveURLFetcherCore(this); 926 g_registry.Get().RemoveURLFetcherCore(this);
877 } 927 }
878 928
879 base::TimeTicks URLFetcherCore::GetBackoffReleaseTime() { 929 base::TimeTicks URLFetcherCore::GetBackoffReleaseTime() {
880 DCHECK(network_task_runner_->BelongsToCurrentThread()); 930 DCHECK(network_task_runner_->BelongsToCurrentThread());
881 931
882 if (original_url_throttler_entry_) { 932 if (original_url_throttler_entry_) {
883 base::TimeTicks original_url_backoff = 933 base::TimeTicks original_url_backoff =
(...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after
1007 } 1057 }
1008 1058
1009 void URLFetcherCore::InformDelegateDownloadDataInDelegateThread( 1059 void URLFetcherCore::InformDelegateDownloadDataInDelegateThread(
1010 scoped_ptr<std::string> download_data) { 1060 scoped_ptr<std::string> download_data) {
1011 DCHECK(delegate_task_runner_->BelongsToCurrentThread()); 1061 DCHECK(delegate_task_runner_->BelongsToCurrentThread());
1012 if (delegate_) 1062 if (delegate_)
1013 delegate_->OnURLFetchDownloadData(fetcher_, download_data.Pass()); 1063 delegate_->OnURLFetchDownloadData(fetcher_, download_data.Pass());
1014 } 1064 }
1015 1065
1016 } // namespace net 1066 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698